題目大意:
給定乙個長度為n的01序列為,現在有m種操作 0a
b 0ab
把[a,b
] [a,
b]
的數全部修改為0 1a
b 1ab
把[a,b
] [a,
b]
的數全部修改為1 2a
b 2ab
把[a,b
] [a,
b]
的所有數取反,就是0->1 1->0 3a
b 3ab
詢問[a
,b] [a,
b]
中一共有多少個0 4a
b 4ab
詢問[a
,b] [a,
b]
中最長有多少個連續的1其中n
≤100000,m
≤100000
n
≤100000,m
≤100000
一看這個資料範圍和題目要求,我們就不難看出這是乙個線段樹題
首先,我們考慮,因為有取反這個操作的存在,所以我們在維護1的資訊的同時,也需要維護0的資訊
然後取反的時候,直接sw
aps wa
p就可以了
對於3詢問,我們只需要維護乙個區間內0的個數和1的個數就可以
而4詢問呢,為了方便合併和求答案
所以對於乙個節點,我們需要維護這個區間左連續最長的1,右連續最長的1 ,還有整個區間最長的連續的1
以及相對應的0的資訊。
合併的時候,如果左區間的連續1的長度覆蓋了整個區間,那麼大區間的左連續的長度等於左區間的左連續加右區間的左連續的長度
其他的情況同理
void up(int root)
之後就是pushdown了,我們發現,這個題有兩種標記。一種是覆蓋,一種是取反
我們考慮 每次覆蓋的之後,這個區間原本的取反的標記就沒有了,所以覆蓋之後要清空覆蓋標記
而下傳的時候,我們要先覆蓋,後取反,不然取反就沒有用了
void pushdown(int root,int l,int r)
else
flag[root]=-1;
}if (rever[root])
}
其他的update都差不多
再就是query的時候,我們需要返回乙個node型別,然後像up的操作一樣進行合併和求答案
直接上**
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int
read()
while (isdigit(ch))
return
x*f;
}struct node;
const int maxn = 1e5+1e2;
node f[maxn*4];
int rever[4
*maxn],flag[4
*maxn];
int n,m;
int a[maxn];
void up(int root)
void pushdown(int root,int l,int r)
else
flag[root]=-1;
}if (rever[root])
}void build(int root,int l,int r)
else
return;
}int mid = (l+r) >> 1;
build(2
*root,l,mid);
build(2
*root+1,mid+1,r);
up(root);
}void update0(int root,int l,int r,int
x,int
y) pushdown(root,l,r);
int mid =(l+r) >> 1;
if (x
<=mid) update0(2
*root,l,mid,x,y);
if (y>mid) update0(2
*root+1,mid+1,r,x,y);
up(root);
}void update1(int root,int l,int r,int
x,int
y) pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x
<=mid) update1(2
*root,l,mid,x,y);
if (y>mid) update1(2
*root+1,mid+1,r,x,y);
up(root);
}void reverse(int root,int l,int r,int
x,int
y) pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x
<=mid) reverse(2
*root,l,mid,x,y);
if (y>mid) reverse(2
*root+1,mid+1,r,x,y);
up(root);
}int querysum(int root,int l,int r,int
x,int
y) pushdown(root,l,r);
int mid = (l+r) >> 1;
int ans=0;
if (x
<=mid) ans+=querysum(2
*root,l,mid,x,y);
if (y>mid) ans+=querysum(2
*root+1,mid+1,r,x,y);
return ans;
}node queryans(int root,int l,int r,int
x,int
y) pushdown(root,l,r);
int mid = (l+r) >> 1;
node ans,ans1,ans2;
ans=ans1=ans2=f[4
*maxn-10];
if (x
<=mid)
if (y>mid)
//cout<<"gg"
<0=ans1.sum0+ans2.sum0;
ans.sum1=ans1.sum1+ans2.sum1;
ans.zuo0=ans1.zuo0;
ans.zuo1=ans1.zuo1;
if (ans1.zuo0==(mid-l+1)) ans.zuo0+=ans2.zuo0;
if (ans1.zuo1==(mid-l+1)) ans.zuo1+=ans2.zuo1;
ans.you0=ans2.you0;
ans.you1=ans2.you1;
if (ans2.you0==(r-mid)) ans.you0+=ans1.you0;
if (ans2.you1==(r-mid)) ans.you1+=ans1.you1;
ans.ans1=max(ans1.ans1,ans2.ans1);
ans.ans1=max(ans.ans1,ans1.you1+ans2.zuo1);
ans.ans0=max(ans1.ans0,ans2.ans0);
ans.ans0=max(ans.ans0,ans1.you0+ans2.zuo0);
return ans;
}int main()
if (opt==1)
if (opt==2)
if (opt==3)
if (opt==4)
//cout<1,1,n,1,6)<<"gg"
0;}
bzoj1858SCOI 序列操作 (線段樹)
題目大意 給定乙個長度為n的01序列為,現在有m種操作 0 a b 把 a,b 的數全部修改為0 1 a b 把 a,b 的數全部修改為1 2 a b 把 a,b 的所有數取反,就是0 1 1 0 3 a b 詢問 a,b 中一共有多少個0 4 a b 詢問 a,b 中最長有多少個連續的1 其中 n...
bzoj1858 Scoi2010 序列操作
bzoj1858 scoi2010 序列操作 一道裸線段樹。的確是比較好想,然而 寫得莫名醜,於是調了很長時間。題解 維護區間中1的總數,左起連續1的個數,右起連續1的個數,最大連續1的個數,0同理。更新的時候左起連續1 0 要考慮左區間全為1 0 延伸到右區間的情況,右起同理。最大連續考慮左區間的...
BZOJ1858 Scoi2010 序列操作
description lxhgww最近收到了乙個01序列,序列裡面包含了n個數,這些數要麼是0,要麼是1,現在對於這個序列有五種變換操作和詢問操作 0 a b 把 a,b 區間內的所有數全變成0 1 a b 把 a,b 區間內的所有數全變成1 2 a b 把 a,b 區間內的所有數全部取反,也就是...