题意:给一个由0,1组成的序列,有两种操作,一种是翻转给定区间的数(0->1,1->0),另一种是查询给定区间内由1组成的子串的最大长度。重点在区间合并和延迟标记。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #include<cmath> #define INF 0x3fffffff using namespace std; const int N=100010; struct Node { int l,r,lsum0,rsum0,msum0,lsum1,rsum1,msum1; int flag;//0不用翻转,1用 int Mid(){ return (l+r)/2; } }tree[4*N]; int a[N]; //合并左右子树 void pushUp(int rt) { int ll=tree[rt*2].r-tree[rt*2].l+1; int rl=tree[rt*2+1].r-tree[rt*2+1].l+1; //1的从左开始最大连续数 tree[rt].lsum1=tree[rt*2].lsum1; //若等于左子树长度,就要加上右子树左边最大 if(tree[rt*2].lsum1==ll){ tree[rt].lsum1+=tree[rt*2+1].lsum1; } //同理,1的从右开始最大连续数 tree[rt].rsum1=tree[rt*2+1].rsum1; if(tree[rt*2+1].rsum1==rl){ tree[rt].rsum1+=tree[rt*2].rsum1; } //此区间的最大子串要么在中间,要么从左开始,要么从右开始,所以最大子串为三种情况最大值。 tree[rt].msum1=max(max(tree[rt*2].msum1,tree[rt*2+1].msum1),tree[rt*2].rsum1+tree[rt*2+1].lsum1); tree[rt].lsum0=tree[rt*2].lsum0; if(tree[rt*2].lsum0==ll){ tree[rt].lsum0+=tree[rt*2+1].lsum0; } tree[rt].rsum0=tree[rt*2+1].rsum0; if(tree[rt*2+1].rsum0==rl){ tree[rt].rsum0+=tree[rt*2].rsum0; } tree[rt].msum0=max(max(tree[rt*2].msum0,tree[rt*2+1].msum0),tree[rt*2].rsum0+tree[rt*2+1].lsum0); } //交换 void Swap(int rt) { swap(tree[rt].lsum0,tree[rt].lsum1); swap(tree[rt].rsum0,tree[rt].rsum1); swap(tree[rt].msum0,tree[rt].msum1); } //从父节点向下更新(lazy) void pushDown(int rt) { if(tree[rt].flag==1){ tree[rt*2].flag^=1; tree[rt*2+1].flag^=1; tree[rt].flag=0; Swap(rt*2); Swap(rt*2+1); } } void build(int rt,int l,int r) { tree[rt].l=l;tree[rt].r=r;tree[rt].flag=0; //初始化每个叶子节点 if(l==r){ if(a[l]==0){ tree[rt].lsum0=tree[rt].rsum0=tree[rt].msum0=1; tree[rt].lsum1=tree[rt].rsum1=tree[rt].msum1=0; } else if(a[l]==1){ tree[rt].lsum0=tree[rt].rsum0=tree[rt].msum0=0; tree[rt].lsum1=tree[rt].rsum1=tree[rt].msum1=1; } return; } int mid=(l+r)/2; build(2*rt,l,mid); build(2*rt+1,mid+1,r); pushUp(rt); } void update(int rt,int l,int r) { if(tree[rt].l==l&&tree[rt].r==r){ tree[rt].flag^=1; Swap(rt); return; } //更新子树 pushDown(rt); if(r<=tree[rt].Mid()){ update(2*rt,l,r); } else if(l>tree[rt].Mid()){ update(2*rt+1,l,r); } else{ update(2*rt,l,tree[rt].Mid()); update(2*rt+1,tree[rt].Mid()+1,r); } //向上合并更新 pushUp(rt); } int query(int rt,int l,int r) { if(tree[rt].l==l&&tree[rt].r==r) { return tree[rt].msum1; } pushDown(rt); int ans; if(r<=tree[rt].Mid()){ ans=query(rt*2,l,r); } else if(l>tree[rt].Mid()){ ans=query(2*rt+1,l,r); } else{ int lr=query(2*rt,l,tree[rt].Mid()); int rr=query(2*rt+1,tree[rt].Mid()+1,r); int a=tree[rt*2].rsum1; if(a>tree[rt*2].r-l+1) a=tree[rt*2].r-l+1; int b=tree[rt*2+1].lsum1; if(b>r-tree[rt*2+1].l+1) b=r-tree[rt*2+1].l+1; ans=max(max(lr,rr),a+b); } pushUp(rt); return ans; } int main() { //freopen("d:\\Test.txt","r",stdin); int n; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); int m; scanf("%d",&m); while(m--){ int op,l,r; scanf("%d%d%d",&op,&l,&r); if(op==0){ cout<<query(1,l,r)<<endl; } else if(op==1){ update(1,l,r); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu3911 Black And White(线段树区间合并)
原文地址:http://blog.csdn.net/u012198382/article/details/48154127