【平衡树】NOI 2005 维护数列
上次学习平衡树就是卡在了这里,现在就以这道题做个小结吧。
题目在这里http://www.lydsy.com/JudgeOnline/problem.php?id=1500
这是NOI以来出的最果的最直接的数据结构题目了,但这明显不代表他简单,第一次做的时候用了2天,现在写起来也是倍感麻烦。
关于这道题的感悟我觉得这个博客说的很好,让我受益很多。
http://www.cppblog.com/MatoNo1/archive/2011/06/21/149121.html
为了做这道题看了很多文章,看到了郭家宝的文章,让我发现了,“原来郭家宝的splay也是用6个if语句写的”!!!!!
竟然写了245行……虽然我的代码也有230行,但是我喜欢换行、如果调整好格式的话应该是在200以内的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** *Prob : NOI2005 -- sequence *Data : 2012-6-25 *Sol : Splay *Author : ZhouHang */ #include <cstdio> #include <cstring> #define oo 1000000000 #define MaxN 500200 using namespace std; struct node { int v,c[2],p,sz,sum,lmax,rmax,midmax,sm; bool rev,d; } T[MaxN+1]; int root,len,res; int open,closd; int a[MaxN],Q[MaxN]; int max(int x,int y) { return x>y?x:y; } int max(int x,int y,int z) { int tmp=x>y?x:y; if (z>tmp) tmp=z; return tmp; } void sc(int _p,int _x,bool _d) { T[_p].c[_d] = _x; T[_x].p = _p; T[_x].d=_d; } //新建结点 void newnode(int n,int _v) { T[n].v = T[n].sum = T[n].lmax = T[n].rmax = T[n].midmax = _v; T[n].c[0] = T[n].c[1] = 0; T[n].sz = 1; T[n].sm = -oo; T[n].rev=0; } //Make_same生效 void sm_opr(int x,int SM) { T[x].sum = T[x].sz * SM; if (SM>0) T[x].lmax=T[x].rmax=T[x].midmax=T[x].sum; else T[x].lmax=T[x].rmax=T[x].midmax=SM; } //旋转生效 void rev_opr(int x) { int c0=T[x].c[0], c1=T[x].c[1]; sc(x,c0,1); sc(x,c1,0); int tmp = T[x].lmax; T[x].lmax = T[x].rmax; T[x].rmax = tmp; } //回收到内存池 void era(int x) { if (!x) return; if (open==MaxN) open=1; else open++; Q[open]=x; era(T[x].c[0]); era(T[x].c[1]); } //传递标识(音'质') void dm(int x) { int SM0=T[x].sm; if (SM0 != -oo) { T[x].v = T[T[x].c[0]].sm = T[T[x].c[1]].sm = SM0; T[x].sm = -oo; sm_opr(T[x].c[0],SM0); sm_opr(T[x].c[1],SM0); } if (T[x].rev) { T[T[x].c[0]].rev=!T[T[x].c[0]].rev; T[T[x].c[1]].rev=!T[T[x].c[1]].rev; T[x].rev=0; rev_opr(T[x].c[0]); rev_opr(T[x].c[1]); } } void upd(int x) { int c0=T[x].c[0], c1=T[x].c[1]; T[x].sz = T[c0].sz + T[c1].sz + 1; T[x].sum = T[c0].sum + T[c1].sum + T[x].v; T[x].lmax = max(T[c0].lmax,T[c0].sum+T[x].v+max(0,T[c1].lmax)); T[x].rmax = max(T[c1].rmax,T[c1].sum+T[x].v+max(0,T[c0].rmax)); T[x].midmax = max(T[c0].midmax, T[c1].midmax, max(T[c0].rmax,0)+T[x].v+max(T[c1].lmax,0)); } void rot(int x) { int y=T[x].p; bool d=T[x].d; if (y==root) { root=x; T[root].p=0; } else sc(T[y].p,x,T[y].d); sc(y,T[x].c[!d],d); sc(x,y,!d); upd(y); } void splay(int x,int r) { int p0,p; while ( (p0=T[x].p)!=r ) { p=T[p0].p; if (p==r) rot(x); else if (T[p0].d==T[x].d) { rot(p0); rot(x); } else { rot(x); rot(x); } } upd(x); } int Find_Kth(int K) { int i=root,S0; while (i) { dm(i); S0 = T[T[i].c[0]].sz+1; if (K==S0) break; else if (K<S0) i=T[i].c[0]; else { K-=S0; i=T[i].c[1]; } } return i; } //MaKe a new Tree int mkt(int l,int r) { if (l>r) return 0; int n0=Q[closd],mid=(l+r)/2; if (closd==MaxN) closd=1; else closd++; newnode(n0,a[mid]); int ll=mkt(l,mid-1); int rr=mkt(mid+1,r); sc(n0,ll,0); sc(n0,rr,1); upd(n0); return n0; } //各种操作 void ins(int pos) { int p0=Find_Kth(pos); splay(p0,0); int p1=Find_Kth(pos+1); splay(p1,root); sc(p1,mkt(1,len),0); upd(p1); upd(p0); } void del(int l,int r) { int p0=Find_Kth(l-1); splay(p0,0); int p1=Find_Kth(r+1); splay(p1,root); int tmp=T[p1].c[0]; sc(p1,0,0); upd(p1); upd(p0); era(tmp); } void mksame(int l,int r,int x) { int p0 = Find_Kth(l-1); splay(p0,0); int p1 = Find_Kth(r+1); splay(p1,root); int n = T[p1].c[0]; T[n].sm = x; sm_opr(n,x); upd(p1); upd(p0); } void reve(int l,int r) { int p0 = Find_Kth(l-1); splay(p0,0); int p1 = Find_Kth(r+1); splay(p1,root); int n = T[p1].c[0]; T[n].rev = !T[n].rev; rev_opr(n); upd(p1); upd(p0); } int get_sum(int l, int r) { int p0 = Find_Kth(l - 1); splay(p0, 0); int p1 = Find_Kth(r + 1); splay(p1, root); int n = T[p1].c[0]; return T[n].sum; } int max_sum() { return T[root].midmax; } //初始化 void prepare() { T[0].sz = T[0].sum = T[0].lmax = T[0].rmax = T[0].midmax =0; for (int i=1; i<=MaxN; i++) Q[i]=i; open = MaxN; closd = 3; newnode(1,-oo); newnode(2,-oo); sc(1,2,1); root = 1; T[root].p = 0; } int main() { freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); prepare(); int m,l,r,x; scanf("%d%d",&len,&m); for (int i=1; i<=len; i++) scanf("%d",&a[i]); //a数组全部插入树中 ins(1); char str[100]; //scanf("%*c"); for (int i=1; i<=m; i++) { scanf("%s",str); if (!strcmp(str, "INSERT")) { scanf("%d%d",&l,&len); for (int j=1; j<=len; j++) scanf("%d",&a[j]); ins(++l); } if (!strcmp(str, "DELETE")) { scanf("%d%d",&l,&r); r += l++; del(l, r); } if (!strcmp(str, "MAKE-SAME")) { scanf("%d%d%d",&l,&r,&x); r += l++; mksame(l, r, x); } if (!strcmp(str, "REVERSE")) { scanf("%d%d", &l, &r); r += l++; reve(l, r); } if (!strcmp(str, "GET-SUM")) { scanf("%d%d", &l, &r); r += l++; printf("%d\n", get_sum(l, r)); } if (!strcmp(str, "MAX-SUM")) printf("%d\n",max_sum()); scanf("%*c"); } fclose(stdin); fclose(stdout); return 0; }