【原题】
对于30%的数据,1<=n, m<=1000
对于100%的数据,1<=n, m<=100000
【分析】真是一道猥琐的线段树的题目。以前我没写过染色等题目,但是还是YY出了譬如最大连续段数的求法。在线段树中还是要记录一下区间左端点数码、右端点数码。后来我越想越复杂,还要记录左(和右)端点如果是1(和0),最长的连续的个数。因为在L~R由L~M和M+1~R转移的时候,最长连续1的个数可能是左区间右端点连续的1和右区间左端点连续的1合并造成的。
此外,其实还是要记录最长连续0的个数,因为要区间取反的。
先挖个坑,以后有空的话再详细的写一下算法。
【代码】
#include<cstdio> #include<algorithm> #define N 100005 #define LL a[L].r-a[L].l+1 #define RR a[R].r-a[R].l+1 #define PP a[P].r-a[P].l+1 #define mid ((a[k].l+a[k].r)>>1) using namespace std; struct Tree { int l,r,lnum,rnum,l1,r1,l0,r0,cover,num,max0,max1; }a[N*3]; int data[N],x,y,opt,temp,n,i,Q; inline void up(int k) { int L=k<<1,R=k<<1|1; a[k].lnum=a[L].lnum;a[k].rnum=a[R].rnum; a[k].l1=a[L].l1;if (a[L].l1==LL) a[k].l1+=a[R].l1; a[k].r1=a[R].r1;if (a[R].r1==RR) a[k].r1+=a[L].r1; a[k].l0=a[L].l0;if (a[L].l0==LL) a[k].l0+=a[R].l0; a[k].r0=a[R].r0;if (a[R].r0==RR) a[k].r0+=a[L].r0; a[k].num=a[L].num+a[R].num; a[k].max1=max(a[L].max1,a[R].max1); if (a[L].rnum&a[R].lnum) a[k].max1=max(a[k].max1,a[L].r1+a[R].l1); a[k].max0=max(a[L].max0,a[R].max0); if ((!a[L].rnum)&(!a[R].lnum)) a[k].max0=max(a[k].max0,a[L].r0+a[R].l0); } inline void build(int k,int l,int r) { a[k].l=l;a[k].r=r; if (l==r) { a[k].lnum=a[k].rnum=a[k].l1=a[k].r1=a[k].num=a[k].max1=data[l]; a[k].l0=a[k].r0=a[k].max0=data[l]^1;return; } build(k<<1,l,mid); build(k<<1|1,mid+1,r); up(k); } inline void update(int P,int add) { if (add==1) { a[P].l1=a[P].r1=a[P].num=a[P].max1=PP; a[P].l0=a[P].r0=a[P].max0=0; a[P].lnum=a[P].rnum=1; } if (add==-1) { a[P].l1=a[P].r1=a[P].num=a[P].max1=a[P].lnum=a[P].rnum=0; a[P].l0=a[P].r0=a[P].max0=PP; } if (add==2) { swap(a[P].l0,a[P].l1);swap(a[P].r0,a[P].r1);swap(a[P].max0,a[P].max1); a[P].lnum^=1;a[P].rnum^=1; a[P].num=PP-a[P].num; } } inline void down(int k,int P) { update(P,temp=a[k].cover); if (temp&1) a[P].cover=temp; if (temp==2) { if (a[P].cover&1) a[P].cover=-a[P].cover; else a[P].cover=2-a[P].cover; } } void work(int k) { if (x<=a[k].l&&a[k].r<=y) { update(k,opt); if (!a[k].cover) a[k].cover=opt; else a[k].cover=(opt&1)?opt:((a[k].cover==2)?0:-a[k].cover); return; } down(k,k<<1);down(k,k<<1|1);a[k].cover=0; if (x<=mid) work(k<<1); if (y>mid) work(k<<1|1); up(k); } int ask(int k) { if (x<=a[k].l&&a[k].r<=y) return (opt==3)?a[k].num:a[k].max1; down(k,k<<1);down(k,k<<1|1);a[k].cover=0; int Mid=(a[k].l+a[k].r)>>1; if (opt==3) return (((x<=Mid)?ask(k<<1):0)+((y>Mid)?ask(k<<1|1):0)); int Max=0; if (x<=Mid) Max=max(Max,ask(k<<1)); if (y>Mid) Max=max(Max,ask(k<<1|1)); if (x<=Mid&&y>Mid) Max=max(Max,min(a[k<<1].r1,Mid-x+1)+min(a[k<<1|1].l1,y-Mid)); return Max; } inline int c(int k) {return (!k)?-1:k;} #define BUF_SIZE 100000 #define OUT_SIZE 100000 bool IOerror=0; inline char nc(){ static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; if (p1==pend){ p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); }return *p1++; } inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} inline void read(int &x){ bool sign=0; char ch=nc(); x=0; for (;blank(ch);ch=nc()); if (IOerror)return; if (ch=='-')sign=1,ch=nc(); for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; if (sign)x=-x; } int main() { read(n);read(Q); for (i=1;i<=n;i++) read(data[i]); build(1,1,n); while (Q--) { read(opt);read(x);x++;read(y);y++; if (opt<3) opt=c(opt),work(1); else printf("%d\n",ask(1)); } return 0; }
bzoj 1858: [Scoi2010] 序列操作 题解,布布扣,bubuko.com
原文:http://blog.csdn.net/jiangshibiao/article/details/36667901