数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列
Posted 既然选择了远方,便只顾风雨兼程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列相关的知识,希望对你有一定的参考价值。
seq2005.in
输出文件:seq2005.out
简单对比时间限制:3 s 内存限制:256 MB
【问题描述】
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
操作编号 |
输入文件中的格式 |
说明 |
1. 插入 |
INSERT_posi_tot_c1_c2_..._ctot |
在当前数列的第 posi 个数字后插入 tot 个数字:c1, c2, …, ctot;若在数列首插 入,则 posi 为 0 |
2. 删除 |
DELETE_posi_tot |
从当前数列的第 posi 个数字开始连续 删除 tot 个数字 |
3. 修改 |
MAKE-SAME_posi_tot_c |
将当前数列的第 posi 个数字开始的连 续 tot 个数字统一修改为 c |
4. 翻转 |
REVERSE_posi_tot |
取出从当前数列的第 posi 个数字开始 的 tot 个数字,翻转后放入原来的位置 |
5. 求和 |
GET-SUM_posi_tot |
计算从当前数列开始的第 posi 个数字 开始的 tot 个数字的和并输出 |
6. 求和最 大的子列 |
MAX-SUM |
求出当前数列中和最大的一段子列, 并输出最大和 |
【输入格式】
输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M表示要进行的操作数目。
第 2 行包含 N 个数字,描述初始时的数列。
以下 M 行,每行一条命令,格式参见问题描述中的表格。
【输出格式】
对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结果,每个答案(数字)占一行。
【输入样例】
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
【输出样例】
-1
10
1
10
【样例说明】
初始时,我们拥有数列 2 -6 3 5 1 -5 -3 6 3
执行操作 GET-SUM 5 4,表示求出数列中从第 5 个数开始连续 4 个数字之和,1+(-5)+(-3)+6 = -1:
2 -6 3 5 1 -5 -3 6 3
执行操作 MAX-SUM,表示要求求出当前数列中最大的一段和,应为 3+5+1+(-5)+(-3)+6+3 = 10:
2 -6 3 5 1 -5 -3 6 3
执行操作 INSERT 8 3 -5 7 2,即在数列中第 8 个数字后插入-5 7 2,
2 -6 3 5 1 -5 -3 6 -5 7 2 3
执行操作 DELETE 12 1,表示删除第 12 个数字,即最后一个:
2 -6 3 5 1 -5 -3 6 -5 7 2
执行操作 MAKE-SAME 3 3 2,表示从第 3 个数开始的 3 个数字,统一修改为 2:
2 -6 3 5 1 -5 -3 6 -5 7 2
改为
2 -6 2 2 2 -5 -3 6 -5 7 2
执行操作 REVERSE 3 6,表示取出数列中从第 3 个数开始的连续 6 个数:
2 -6 2 2 2 -5 -3 6 -5 7 2
如上所示的灰色部分 2 2 2 -5 -3 6,翻转后得到 6 -3 -5 2 2 2,并放回原来位置:
2 -6 6 -3 -5 2 2 2 -5 7 2
最后执行 GET-SUM 5 4 和 MAX-SUM,不难得到答案 1 和 10。
2 -6 6 -3 -5 2 2 2 -5 7 2
【评分方法】
本题设有部分分,对于每一个测试点:
- 如果你的程序能在输出文件正确的位置上打印 GET-SUM 操作的答案,你可以得到该测试点 60%的分数;
- 如果你的程序能在输出文件正确的位置上打印 MAX-SUM 操作的答案,你可以得到该测试点 40%的分数;
- 以上两条的分数可以叠加,即如果你的程序正确输出所有 GET-SUM 和MAX-SUM 操作的答案,你可以得到该测试点 100%的分数。
请注意:如果你的程序只能正确处理某一种操作,请确定在输出文件正确的位置上打印结果,即必须为另一种操作留下对应的行,否则我们不保证可以正确评分。
【数据规模和约定】
- 你可以认为在任何时刻,数列中至少有 1 个数。
- 输入数据一定是正确的,即指定位置的数在数列中一定存在。
- 50%的数据中,任何时刻数列中最多含有 30 000 个数;
- 100%的数据中,任何时刻数列中最多含有 500 000 个数。
- 100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
- 100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件大小不超过 20MBytes。
这道题需要注意细节,写之前请理清思路!!!
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=5000010; 6 const int INF=1000000000; 7 int fa[maxn],ch[maxn][2],sz[maxn],key[maxn]; 8 int mark[maxn],flip[maxn],sum[maxn],n,Q; 9 int lx[maxn],rx[maxn],mx[maxn],rt,cnt; 10 char s[15]; 11 void Push_up(int x){ 12 sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; 13 sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x]; 14 lx[x]=max(lx[ch[x][0]],key[x]+sum[ch[x][0]]+lx[ch[x][1]]); 15 rx[x]=max(rx[ch[x][1]],key[x]+sum[ch[x][1]]+rx[ch[x][0]]); 16 mx[x]=max(max(mx[ch[x][0]],mx[ch[x][1]]),key[x]+rx[ch[x][0]]+lx[ch[x][1]]); 17 } 18 19 void Cover(int x,int d){ 20 if(!x)return; 21 key[x]=d;mark[x]=1; 22 sum[x]=sz[x]*d; 23 if(d>0)lx[x]=rx[x]=mx[x]=sum[x]; 24 else lx[x]=rx[x]=0,mx[x]=d; 25 } 26 27 void Flip(int x){ 28 if(!x)return; 29 swap(ch[x][0],ch[x][1]); 30 swap(lx[x],rx[x]); //mod Kuang_bin 31 flip[x]^=1; 32 } 33 34 void Push_down(int x){ 35 if(mark[x]){ 36 Cover(ch[x][0],key[x]); 37 Cover(ch[x][1],key[x]); 38 mark[x]=0; 39 } 40 if(flip[x]){ 41 Flip(ch[x][0]); 42 Flip(ch[x][1]); 43 flip[x]=0; 44 } 45 } 46 47 void Rotate(int x){ 48 int y=fa[x],g=fa[y],c=ch[y][1]==x; 49 ch[y][c]=ch[x][c^1];fa[ch[y][c]]=y; 50 ch[x][c^1]=y;fa[y]=x;fa[x]=g; 51 if(g)ch[g][ch[g][1]==y]=x; 52 Push_up(y); 53 } 54 55 void Splay(int x,int g=0){ 56 for(int y;(y=fa[x])!=g;Rotate(x)) 57 if(fa[y]!=g) 58 Rotate((ch[fa[y]][1]==y)==(ch[y][1]==x)?y:x); 59 if(!g)rt=x; 60 Push_up(x); 61 } 62 63 void Rtr(int k,int g=0){ 64 int p=rt; 65 while(true){ 66 Push_down(p); 67 if(sz[ch[p][0]]+1==k)break; 68 if(sz[ch[p][0]]+1<k){ 69 k-=sz[ch[p][0]]+1; 70 p=ch[p][1]; 71 } 72 else 73 p=ch[p][0]; 74 } 75 Splay(p,g); 76 } 77 78 int Insert(int x,int l,int r){ 79 int mid=(l+r)>>1,p=++cnt; 80 fa[p]=x;sz[p]=1; 81 if(l<mid)ch[p][0]=Insert(p,l,mid-1); 82 scanf("%d",&key[p]); 83 if(r>mid)ch[p][1]=Insert(p,mid+1,r); 84 Push_up(p); 85 return p; 86 } 87 88 void Init(){ 89 cnt=2;rt=1; 90 mx[1]=mx[2]=-INF; 91 fa[2]=1;ch[1][1]=2; 92 ch[ch[rt][1]][0]=Insert(ch[rt][1],1,n); 93 Push_up(ch[rt][1]); 94 Push_up(rt); 95 } 96 97 int main(){ 98 freopen("seq2005.in","r",stdin); 99 freopen("seq2005.out","w",stdout); 100 scanf("%d%d",&n,&Q); 101 Init();mx[0]=-INF; 102 int l,r,x,d,tot=n+2; 103 while(Q--){ 104 scanf("%s",s); 105 if(!strcmp(s,"MAX-SUM")){ 106 Rtr(1); 107 Rtr(tot,rt); 108 Push_down(rt); 109 Push_down(ch[rt][1]); 110 printf("%d\n",mx[ch[ch[rt][1]][0]]); 111 } 112 else if(!strcmp(s,"INSERT")){ 113 scanf("%d%d",&l,&x);l+=1; 114 Rtr(l);Rtr(l+1,rt); 115 Push_down(rt);tot+=x; 116 Push_down(ch[rt][1]); 117 ch[ch[rt][1]][0]=Insert(ch[rt][1],1,x); 118 Push_up(ch[rt][1]); 119 Push_up(rt); 120 } 121 else if(!strcmp(s,"DELETE")){ 122 scanf("%d%d",&l,&x);r=l+x+1; 123 Rtr(l);Rtr(r,rt);tot-=x; 124 ch[ch[rt][1]][0]=0; 125 Push_up(ch[rt][1]); 126 Push_up(rt); 127 } 128 else if(!strcmp(s,"REVERSE")){ 129 scanf("%d%d",&l,&x);r=l+x+1; 130 Rtr(l);Rtr(r,rt); 131 Flip(ch[ch[rt][1]][0]); 132 Push_up(ch[rt][1]); 133 Push_up(rt); 134 } 135 else if(!strcmp(s,"MAKE-SAME")){ 136 scanf("%d%d%d",&l,&x,&d);r=l+x+1; 137 Rtr(l);Rtr(r,rt); 138 Push_down(rt); 139 Push_down(ch[rt][1]); 140 Cover(ch[ch[rt][1]][0],d); 141 Push_up(ch[rt][1]); 142 Push_up(rt); 143 } 144 else if(!strcmp(s,"GET-SUM")){ 145 scanf("%d%d",&l,&x);r=l+x+1; 146 Rtr(l);Rtr(r,rt); 147 Push_down(rt); 148 Push_down(ch[rt][1]); 149 printf("%d\n",sum[ch[ch[rt][1]][0]]); 150 } 151 } 152 return 0; 153 }
以上是关于数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列的主要内容,如果未能解决你的问题,请参考以下文章