您的位置:首页 > 其它

HYSBZ 1858(Scoi2010) 序列操作(线段树+区间合并)

2016-03-24 11:02 429 查看

序列操作

Description

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 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]区间内总共有多少个1 4 a b 询问[a, b]区间内最多有多少个连续的1 对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目 第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作="" <="" iv="">

Output

对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

Sample Input

10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9


Sample Output

5
2
6
5


解题思路:

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]区间内总共有多少个1

4 a b 询问[a, b]区间内最多有多少个连续的1

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn = 100005;

struct node{
int l,r;
int l1,r1; //左右连续1
int l0,r0; //左右连续0
int change; //-1 无操作 2取反,0全0 1全1
int sum1,sum0; //最大连续1,0
int all1,all0; //所有1,0
}tree[maxn*3];
int a[maxn];

//由下向上合并
//tree[id]的延迟标记是指延迟tree[id]的两个孩子的操作,而tree[id]已经完成该操作
void pushup(int id){
int lLen = tree[id<<1].r-tree[id<<1].l+1;
int rLen = tree[id<<1|1].r-tree[id<<1|1].l+1;

tree[id].l1 = tree[id<<1].l1;
if(tree[id<<1].l1 == lLen)
tree[id].l1 += tree[id<<1|1].l1;//左连续1的个数
tree[id].r1 = tree[id<<1|1].r1;
if(tree[id<<1|1].r1 == rLen)
tree[id].r1 += tree[id<<1].r1;//右连续1的个数
tree[id].sum1 = max(tree[id<<1].sum1,tree[id<<1|1].sum1);
tree[id].sum1 = max(tree[id].sum1,tree[id<<1].r1+tree[id<<1|1].l1);//最大连续1=max(左边,右边,中间合并)
tree[id].all1 = tree[id<<1].all1+tree[id<<1|1].all1; //所有1

tree[id].l0 = tree[id<<1].l0;
if(tree[id<<1].l0 == lLen)
tree[id].l0 += tree[id<<1|1].l0;
tree[id].r0 = tree[id<<1|1].r0;
if(tree[id<<1|1].r0 == rLen)
tree[id].r0 += tree[id<<1].r0;
tree[id].sum0 = max(tree[id<<1].sum0,tree[id<<1|1].sum0);
tree[id].sum0 = max(tree[id].sum0,tree[id<<1].r0+tree[id<<1|1].l0);
tree[id].all0 = tree[id<<1].all0+tree[id<<1|1].all0;
}

void pushdown(int id){
if(tree[id].change != -1){
int lLen = tree[id<<1].r-tree[id<<1].l+1;
int rLen = tree[id<<1|1].r-tree[id<<1|1].l+1;
if(tree[id].change == 0){ //set all 0
tree[id<<1].change = tree[id<<1|1].change = 0;
tree[id].change = -1;
tree[id<<1].l1 = tree[id<<1].r1 = tree[id<<1].sum1 = tree[id<<1].all1=0;
tree[id<<1].l0 = tree[id<<1].r0 = tree[id<<1].sum0 = tree[id<<1].all0 = lLen;
tree[id<<1|1].l1 = tree[id<<1|1].r1 = tree[id<<1|1].sum1 = tree[id<<1|1].all1 = 0;
tree[id<<1|1].l0 = tree[id<<1|1].r0 = tree[id<<1|1].sum0 = tree[id<<1|1].all0 = rLen;
return ;
}
if(tree[id].change == 1){//set all 1
tree[id<<1].change = tree[id<<1|1].change = 1;
tree[id].change = -1;
tree[id<<1].l1 = tree[id<<1].r1 = tree[id<<1].sum1 = tree[id<<1].all1=lLen;
tree[id<<1].l0 = tree[id<<1].r0 = tree[id<<1].sum0 = tree[id<<1].all0=0;
tree[id<<1|1].l1 = tree[id<<1|1].r1 = tree[id<<1|1].sum1 = tree[id<<1|1].all1=rLen;
tree[id<<1|1].l0 = tree[id<<1|1].r0 = tree[id<<1|1].sum0 = tree[id<<1|1].all0=0;
return ;
}
if(tree[id].change == 2){//0->1 1->0
tree[id].change = -1;
if(tree[id<<1].change == -1){//如果tree[id<<1]没有操作,则直接取反
tree[id<<1].change = 2;
}
else if(tree[id<<1].change==0){//如果tree[id<<1]已经标记为置0,取反后为置1
tree[id<<1].change = 1;
}
else if(tree[id<<1].change == 1){//如果tree[id<<1]已经标记为置1,取反后为置0
tree[id<<1].change = 0;
}
else if(tree[id<<1].change == 2){//如果tree[id<<1]已经取反,再次取反相当于没操作
tree[id<<1].change = -1;
}
swap(tree[id<<1].l0,tree[id<<1].l1); //tree[id<<1]进行取反操作,0,1的标记都要互换
swap(tree[id<<1].r0,tree[id<<1].r1);
swap(tree[id<<1].sum0,tree[id<<1].sum1);
swap(tree[id<<1].all0,tree[id<<1].all1);
//id<<1|1 同 id<<1
if (tree[id<<1|1].change == -1){
tree[id<<1|1].change = 2;
}
else if(tree[id<<1|1].change == 0){
tree[id<<1|1].change = 1;
}
else if (tree[id<<1|1].change == 1){
tree[id<<1|1].change = 0;
}
else if (tree[id<<1|1].change == 2){
tree[id<<1|1].change = -1;
}
swap(tree[id<<1|1].l0,tree[id<<1|1].l1);
swap(tree[id<<1|1].r0,tree[id<<1|1].r1);
swap(tree[id<<1|1].sum0,tree[id<<1|1].sum1);
swap(tree[id<<1|1].all0,tree[id<<1|1].all1);
}
}
}

void build(int id,int l,int r){
tree[id].l = l;
tree[id].r = r;
tree[id].change = -1;
if(l==r){
tree[id].l1 = tree[id].r1 = tree[id].sum1 = tree[id].all1 = a[l];
tree[id].l0 = tree[id].r0 = tree[id].sum0 = tree[id].all0 = 1-a[l];
return ;
}
int mid = (tree[id].l+tree[id].r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}

void update(int id,int l,int r,int op){
if(tree[id].l == l && tree[id].r == r){
//如果是2号操作,需要考虑原来的操作
if(op == 2){
if(tree[id].change == -1)
tree[id].change = 2;
else if(tree[id].change == 0)
tree[id].change = 1;
else if(tree[id].change == 1)
tree[id].change = 0;
else if(tree[id].change == 2)
tree[id].change = -1;
}else{
//置0,1操作和原来的操作没关系
tree[id].change = op;
}
if(op == 0){
//该区间置0
tree[id].l1 = tree[id].r1 = tree[id].sum1 = tree[id].all1 = 0;
tree[id].l0 = tree[id].r0 = tree[id].sum0 = tree[id].all0 = tree[id].r-tree[id].l+1;
}else if(op == 1){
//该区间置1
tree[id].l1 = tree[id].r1 = tree[id].sum1 = tree[id].all1 = tree[id].r-tree[id].l+1;
tree[id].l0 = tree[id].r0 = tree[id].sum0 = tree[id].all0 = 0;
}
else if(op==2){
//该区间取反
swap(tree[id].l0,tree[id].l1);
swap(tree[id].r0,tree[id].r1);
swap(tree[id].sum0,tree[id].sum1);
swap(tree[id].all0,tree[id].all1);
}
return ;
}
pushdown(id); //如果操作的区间为当前区间的子区间,则要把当前区间的change传到子区间
int mid = (tree[id].l+tree[id].r)>>1;
if(r <= mid)
update(id<<1,l,r,op);
else{
if(l > mid)
update(id<<1|1,l,r,op);
else{
update(id<<1,l,mid,op);
update(id<<1|1,mid+1,r,op);
}
}
pushup(id);//子区间修改完成后,要向父区间合并信息
}

//op == 1求所有1 op == 0求最大连续1
int query(int id,int l,int r,int op){
if(tree[id].l == l && tree[id].r == r){
if(op == 1)
return tree[id].all1;
return tree[id].sum1;
}
pushdown(id);
int mid = (tree[id].l+tree[id].r)>>1;
if(r <= mid)
return query(id<<1,l,r,op);
else{
if(l > mid)
return query(id<<1|1,l,r,op);
else{
if(op == 1)
return query(id<<1,l,mid,op)+query(id<<1|1,mid+1,r,op);
int ans,ans1,ans2;
ans1 = query(id<<1,l,mid,op);
ans2 = query(id<<1|1,mid+1,r,op);
ans = max(ans1,ans2);
ans = max(ans,min(tree[id<<1].r1,mid-l+1)+min(tree[id<<1|1].l1,r-mid)); //r-mid=r-(mid+1)+1
return ans;
}
}
}

int main(){
int n,q;
while(~scanf("%d%d",&n,&q)){
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
build(1,1,n);
while(q--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
x++;
y++;
if(op == 0)
update(1,x,y,0);
else if(op == 1)
update(1,x,y,1);
else if(op == 2)
update(1,x,y,2);
else if(op == 3){
int ans = query(1,x,y,1);
printf("%d\n",ans);
}
else if(op == 4){
int ans = query(1,x,y,0);
printf("%d\n",ans);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: