NOI2005 维修数列
昨天A掉的这题,然后伸展树还有最后一题没敲。很BT的一题,但是感觉学习伸展树不做这道题不算真正学过吧。 这道题多了一个操作,求子序列和的最大值。这个东西怎么维护?其实和学习线段树的时候很经典的那个Hotel基本一样,维护一个最左端的和的最大值,维护一个最右端和的最大值,维护一个最大值,维护一个区间和。然后区间合并的操作就好写了,不过写的时候细节的地方要特别注意一下,例如,没有左节点的情况。(当然每次pushup,pushdown操作的时候都可以加上特判)。这里还有一点要特别注意一下,就是每次翻转的时候:除了左右子节点要翻转之外,还需要将每个节点的lmax_sum,rmax_sum进行交换(这个特别注意一下)。然后其他操作也没有什么难实现的东西。
交了20+发,终于过了,一开始超时居然是因为没有进行内存回收,(话说这样为什么返回的是超时啊,不应该是RE嘛),改掉以后就是一直PushDown操作写跪。
下面附上AC代码:
/************************************************************** Problem: 1500 User: hqwhqwhq Language: C++ Result: Accepted Time:6136 ms Memory:29772 kb ****************************************************************/ #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <map> #define INF (1<<30) #define LL long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define Key_Tree ch[ch[root][1]][0] #define MAXN 550000 using namespace std; int n,m; int num[MAXN]; struct SplayTree{ int ch[MAXN][2],sz[MAXN],pre[MAXN],key[MAXN],root,tot1,tot2,sum[MAXN],maxx[MAXN],lmaxx[MAXN],rmaxx[MAXN]; int s[MAXN]; bool lazy[MAXN]; int cvr[MAXN]; int flip[MAXN]; //固定部分,不需要修改 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); } void Splay(int x,int goal){ Push_Down(x); while(pre[x] != goal){ Push_Down(pre[pre[x]]); Push_Down(pre[x]); Push_Down(x); if(pre[pre[x]] == goal){ Rotate(x,ch[pre[x]][0] == x); } else{ int y = pre[x]; int kind = (ch[pre[y]][0] == y); if(ch[y][kind] == x){ Rotate(x,!kind); Rotate(x,kind); } else{ Rotate(y,kind); Rotate(x,kind); } } } Push_Up(x); if(!goal) root = x; } void RotateTo(int k,int goal){ int x = root; Push_Down(x); while(sz[ch[x][0]] != k){ if(k < sz[ch[x][0]]){ x = ch[x][0]; } else{ k -= (sz[ch[x][0]]+1); x = ch[x][1]; } Push_Down(x); } Splay(x,goal); } //以上为固定部分,不需要修改!!! //debug部分copy from hh void Treaval(int x) { //Push_Down(x); if(x) { Treaval(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,key = %2d,sum = %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],key[x],sum[x]); Treaval(ch[x][1]); } } void debug() {printf("%d\n",root);Treaval(root);} //以上debug void NewNode(int& x,int father,int k){ if(tot2) x = s[tot2--]; else x = ++tot1; pre[x] = father; sum[x] = maxx[x] = lmaxx[x] = rmaxx[x] = key[x] = k; if(x == 1 || x == 2) maxx[x] = lmaxx[x] = rmaxx[x] = -INF; ch[x][0] = ch[x][1] = 0; sz[x] = 1; lazy[x] = false; cvr[x] = 0; flip[x] = 0; } void Update_Flip(int x){ if(!x) return; swap(lmaxx[x],rmaxx[x]); swap(ch[x][0],ch[x][1]); flip[x] ^= 1; } void Update_Same(int x,int v){ if(!x) return; key[x] = v; sum[x] = v * sz[x]; lmaxx[x] = rmaxx[x] = maxx[x] = max(v,sum[x]); cvr[x] = v; lazy[x] = true; } void Push_Up(int x){ sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + key[x]; if(ch[x][0] == 0) lmaxx[x] = key[x] + max(0,lmaxx[ch[x][1]]); else lmaxx[x] = max(lmaxx[ch[x][0]],max(sum[ch[x][0]] + key[x],sum[ch[x][0]] + key[x] + lmaxx[ch[x][1]])); if(ch[x][1] == 0) rmaxx[x] = key[x] + max(0,rmaxx[ch[x][0]]); else rmaxx[x] = max(rmaxx[ch[x][1]],max(sum[ch[x][1]] + key[x],sum[ch[x][1]] + key[x] + rmaxx[ch[x][0]])); int t = max(maxx[ch[x][0]],maxx[ch[x][1]]); maxx[x] = key[x] + max(0,rmaxx[ch[x][0]]) + max(0,lmaxx[ch[x][1]]); maxx[x] = max(maxx[x],t); } void Push_Down(int x){ if(flip[x]){ Update_Flip(ch[x][0]); Update_Flip(ch[x][1]); flip[x] = 0; } if(lazy[x]){ Update_Same(ch[x][0],cvr[x]); Update_Same(ch[x][1],cvr[x]); lazy[x] = false; } } void Build(int& x,int l,int r,int father){ if(l > r) return; int mid = (l+r) >> 1; NewNode(x,father,num[mid]); Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init(){ lmaxx[0] = rmaxx[0] = maxx[0] = -INF; sum[0] = 0; sz[0] = 0; root = tot1 = tot2 = 0; sz[0] = 0; NewNode(root,0,0); NewNode(ch[root][1],root,0); sz[root] = 2; Build(Key_Tree,0,n-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void Erase(int x){ if(!x) return; s[++tot2] = x; Erase(ch[x][0]); Erase(ch[x][1]); } void Insert(int l,int len){ RotateTo(l,0); RotateTo(l+1,root); Build(Key_Tree,0,len-1,ch[root][1]); Push_Up(ch[root][1]); Push_Up(root); } void Delete(int l,int r){ RotateTo(l-1,0); RotateTo(r+1,root); Erase(Key_Tree); Key_Tree = 0; Push_Up(ch[root][1]); Push_Up(root); } void Modify(int l,int r,int v){ RotateTo(l-1,0); RotateTo(r+1,root); lazy[Key_Tree] = true; Update_Same(Key_Tree,v); Push_Up(ch[root][1]); Push_Up(root); } void Reverse(int l,int r){ RotateTo(l-1,0); RotateTo(r+1,root); Update_Flip(Key_Tree); Push_Up(ch[root][1]); Push_Up(root); } int Get_Sum(int l,int r){ RotateTo(l-1,0); RotateTo(r+1,root); return sum[Key_Tree]; } int Max_Sum(){ Splay(1,0); Splay(2,root); return maxx[Key_Tree]; } int Get_Pre(int x){ Push_Down(x); x = ch[x][0]; while(x){ Push_Down(x); while(ch[x][1]){ x = ch[x][1]; Push_Down(x); } return x; } return -1; } int Get_Next(int x){ Push_Down(x); x = ch[x][1]; while(x){ Push_Down(x); while(ch[x][0]){ x = ch[x][0]; Push_Down(x); } return x; } return -1; } }spt; int main() { //freopen("test.in","r",stdin); while(~scanf("%d%d",&n,&m)){ FOR(i,0,n) scanf("%d",&num[i]); spt.Init(); char str[20]; FOR(i,0,m){ scanf("%s",str); if(strcmp(str,"INSERT") == 0){ int pos,cnt; scanf("%d%d",&pos,&cnt); FOR(i,0,cnt) scanf("%d",&num[i]); spt.Insert(pos,cnt); } else if(strcmp(str,"DELETE") == 0){ int pos,cnt; scanf("%d%d",&pos,&cnt); spt.Delete(pos,pos+cnt-1); } else if(strcmp(str,"MAKE-SAME") == 0){ int pos,cnt,v; scanf("%d%d%d",&pos,&cnt,&v); spt.Modify(pos,pos+cnt-1,v); } else if(strcmp(str,"REVERSE") == 0){ int pos,cnt; scanf("%d%d",&pos,&cnt); spt.Reverse(pos,pos+cnt-1); } else if(strcmp(str,"GET-SUM") == 0){ int pos,cnt; scanf("%d%d",&pos,&cnt); printf("%d\n",spt.Get_Sum(pos,pos+cnt-1)); } else{ printf("%d\n",spt.Max_Sum()); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。