NOI 2005 维修数列
典型的伸展树模板题
参考 http://www.cnblogs.com/kuangbin/archive/2013/08/28/3287822.html
#include <iostream> #include <algorithm> #include <string> #include <cmath> #include <cstdio> using namespace std; #define Key_value ch[ch[root][1]][0] const int MAXN = 500010; const int INF = -(1<<30); int pre[MAXN],ch[MAXN][2],key[MAXN],sz[MAXN]; int root,tot1; int sum[MAXN],rev[MAXN],same[MAXN]; int lx[MAXN],rx[MAXN],mx[MAXN]; int s[MAXN],tot2;//内存池和容量 int a[MAXN]; int n,q; void NewNode(int &r,int father,int k) { if(tot2) r = s[tot2--]; //取的时候是tot2--,存的时候就是++tot2 else r = ++tot1; pre[r] = father; ch[r][0] = ch[r][1] = 0; key[r] = k; sum[r] = k; rev[r] = same[r] = 0; lx[r] = rx[r] = mx[r] = k; sz[r] = 1; } void Update_Rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); swap(lx[r],rx[r]); rev[r] ^= 1; } void Update_Same(int r,int v) { if(!r)return; key[r] = v; sum[r] = v*sz[r]; lx[r] = rx[r] = mx[r] = max(v,v*sz[r]); same[r] = 1; } void push_up(int rt) //更新信息 { int lson = ch[rt][0], rson = ch[rt][1]; sz[rt] = sz[lson] + sz[rson] + 1; sum[rt] = sum[lson] + sum[rson] + key[rt]; lx[rt] = max(lx[lson],sum[lson] + key[rt] + max(0,lx[rson])); rx[rt] = max(rx[rson],sum[rson] + key[rt] + max(0,rx[lson])); mx[rt] = max(0,rx[lson]) + key[rt] + max(0,lx[rson]); mx[rt] = max(mx[rt],max(mx[lson],mx[rson])); } void push_down(int r) //消除该节点的same和rev { if(same[r]) { Update_Same(ch[r][0],key[r]); Update_Same(ch[r][1],key[r]); same[r] = 0; } if(rev[r]) { Update_Rev(ch[r][0]); Update_Rev(ch[r][1]); rev[r] = 0; } } void Build(int &x,int l,int r,int father) //建树 { if(l > r)return; int mid = (l+r)/2; NewNode(x,father,a[mid]); Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); push_up(x); } void Init() { root = tot1 = tot2 = 0; ch[root][0] = ch[root][1] = sz[root] = pre[root] = 0; same[root] = rev[root] = sum[root] = key[root] = 0; lx[root] = rx[root] = mx[root] = INF; NewNode(root,0,INF); //NewNode(int &r,int father,int key) NewNode(ch[root][1],root,INF); //这里先加两个节点其实就是在数组的前后加两个数 for(int i = 0;i < n;i++) scanf("%d",&a[i]); //Build(int &x,int l,int r,int father) Build(Key_value,0,n-1,ch[root][1]); // Key_value—>ch[ch[root][1]][0] push_up(ch[root][1]); push_up(root); } //旋转,kind,0为左旋,1为右旋 void Rotate(int x,int kind) { int y = pre[x]; push_down(y); push_down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y] = x; pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; push_up(y); } //Splay调整,将r结点调整到goal下面 void Splay(int r,int goal) { push_down(r); while(pre[r] != goal) { if(pre[pre[r]] == goal) { push_down(pre[r]); push_down(r); Rotate(r,ch[pre[r]][0] == r); } else { push_down(pre[pre[r]]); push_down(pre[r]); push_down(r); int y = pre[r]; int kind = ch[pre[y]][0]==y; if(ch[y][kind] == r) { Rotate(r,!kind); Rotate(r,kind); } else { Rotate(y,kind); Rotate(r,kind); } } } push_up(r); if(goal == 0) root = r; } int Get_kth(int r,int k) { push_down(r); int t = sz[ch[r][0]] + 1; if(t == k)return r; if(t > k)return Get_kth(ch[r][0],k); else return Get_kth(ch[r][1],k-t); }//在第pos个数后面插入tot个数 void Insert(int pos,int tot) { for(int i = 0;i < tot;i++)scanf("%d",&a[i]); Splay(Get_kth(root,pos+1),0); Splay(Get_kth(root,pos+2),root); Build(Key_value,0,tot-1,ch[root][1]); push_up(ch[root][1]); push_up(root); } //删除子树 void DeleteTree(int r) { if(!r)return; s[++tot2] = r; DeleteTree(ch[r][0]); DeleteTree(ch[r][1]); } //从第pos个数开始连续删除tot个数 void Delete(int pos,int tot) { Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+tot+1),root); DeleteTree(Key_value); pre[Key_value] = 0; Key_value = 0; push_up(ch[root][1]); push_up(root); } //将从第pos个数开始的连续的tot个数修改为c void Make_Same(int pos,int tot,int c) { Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+tot+1),root); Update_Same(Key_value,c); push_up(ch[root][1]); push_up(root); } //将第pos个数开始的连续tot个数进行反转 void Reverse(int pos,int tot) { Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+tot+1),root); Update_Rev(Key_value); push_up(ch[root][1]); push_up(root); } //得到第pos个数开始的tot个数的和 int Get_Sum(int pos,int tot) { Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+tot+1),root); return sum[Key_value]; } //得到第pos个数开始的tot个数中最大的子段和 int Get_MaxSum(int pos,int tot) { Splay(Get_kth(root,pos),0); Splay(Get_kth(root,pos+tot+1),root); return mx[Key_value]; } int main() { while(scanf("%d%d",&n,&q) == 2) { Init(); char op[20]; int x,y,z; while(q--) { scanf("%s",op); if(op[0]=='I') { scanf("%d%d",&x,&y); Insert(x,y); } else if(op[0]=='D') { scanf("%d%d",&x,&y); Delete(x,y); } else if(op[0]=='R') { scanf("%d%d",&x,&y); Reverse(x,y); } else if(op[0]=='G') { scanf("%d%d",&x,&y); printf("%d\n",Get_Sum(x,y)); } else if(op[0]=='M'){ if(op[2]=='X'){ printf("%d\n",Get_MaxSum(1,sz[root]-2)); } else { scanf("%d%d%d",&x,&y,&z); Make_Same(x,y,z); } } } } return 0; }