请写一个程序,要求维护一个数列,支持以下 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。
splay维护数列模板题,我们认为该splay的中序遍历即为原数列,那么处理区间只需将该区间左边界点左相邻点旋转至树根,将区间右边界点右相邻点旋转至树根右儿子,则树根右儿子的左儿子的子树即为所要处理的区间,
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <string> using namespace std; string s; const int maxn=500000+10; queue<int>q; const int INF=0x7fffffff; int tr[maxn][3]; int root; int rotated[maxn]={0}; long long summ[maxn]={0}; long long maxx[maxn]={0}; int fa[maxn]; int n; int id[maxn]; int a[maxn]; int v[maxn]; long long lmax[maxn]; long long rmax[maxn]; int size[maxn]; int cnt; int tag[maxn]; inline void pushup(int x){ int l=tr[x][0],r=tr[x][1]; summ[x]=summ[l]+summ[r]+v[x]; size[x]=size[l]+size[r]+1; maxx[x]=max(maxx[l],maxx[r]); maxx[x]=max(maxx[x],rmax[l]+v[x]+lmax[r]); lmax[x]=max(lmax[l],summ[l]+v[x]+lmax[r]); rmax[x]=max(rmax[r],summ[r]+v[x]+rmax[l]); } inline void pushdown(int x){ int l=tr[x][0],r=tr[x][1]; if(tag[x]){ rotated[x]=tag[x]=0; if(l) tag[l]=1,v[l]=v[x],summ[l]=v[x]*size[l]; if(r) tag[r]=1,v[r]=v[x],summ[r]=v[x]*size[r]; if(v[x]>=0){ if(l) lmax[l]=rmax[l]=maxx[l]=summ[l]; if(r) lmax[r]=rmax[r]=maxx[r]=summ[r]; } else { if(l) lmax[l]=rmax[l]=0,maxx[l]=v[x]; if(r) lmax[r]=rmax[r]=0,maxx[r]=v[x]; } } if(rotated[x]){ swap(tr[l][0],tr[l][1]); swap(tr[r][0],tr[r][1]); swap(lmax[l],rmax[l]); swap(lmax[r],rmax[r]); rotated[l]^=1; rotated[r]^=1; rotated[x]^=1; } } inline void rotate(int x,int& o){ int l,r; int y,z; y=fa[x],z=fa[y]; l=(x==tr[y][1]); r=1-l; if(y==o) o=x; else tr[z][tr[z][1]==y]=x; fa[tr[x][r]]=y; fa[y]=x; fa[x]=z; tr[y][l]=tr[x][r]; tr[x][r]=y; pushup(y); pushup(x); } inline void splay(int x,int& k){ int y,z; while(x!=k){ y=fa[x],z=fa[y]; if(y!=k){ if((y==tr[z][1])^(x==tr[y][1])) rotate(x,k); else rotate(y,k); } rotate(x,k); } } inline int find(int o,int k){ pushdown(o); int l=tr[o][0],r=tr[o][1]; if(size[l]+1==k) return o; else if(size[l]>=k) return find(l,k); else return find(r,k-size[l]-1); } inline void dec(int x){ if(!x) return; int l=tr[x][0],r=tr[x][1]; dec(l); dec(r); q.push(x); fa[x]=tr[x][0]=tr[x][1]=0; tag[x]=rotated[x]=0; } inline int spilt(int o,int tot){ int x=find(root,o),y=find(root,o+tot+1); splay(x,root); splay(y,tr[x][1]); return tr[y][0]; } inline void Sum(int o,int k){ int x=spilt(o,k); printf("%lld\n",summ[x]); } inline void modify(int k,int tot,int val){ int x=spilt(k,tot),y=fa[x]; v[x]=val; tag[x]=1; summ[x]=size[x]*val; if(val>=0) lmax[x]=rmax[x]=maxx[x]=summ[x]; else lmax[x]=rmax[x]=0,maxx[x]=val; pushup(y); pushup(fa[y]); } inline void rev(int o,int k){ int x=spilt(o,k); int y=fa[x]; if(!tag[x]){ swap(lmax[x],rmax[x]); swap(tr[x][0],tr[x][1]); rotated[x]^=1; pushup(y); pushup(fa[y]); } } inline void del(int o,int k){ int x=spilt(o,k); int y=fa[x]; dec(x); tr[y][0]=0; pushup(y); pushup(fa[y]); } inline void build(int l,int r,int f){ if(l>r) return; int mid=(l+r)>>1,now=id[mid],last=id[f]; if(l==r){ summ[now]=a[l]; size[now]=1; tag[now]=0; rotated[now]=0; if(a[l]>=0) lmax[now]=rmax[now]=maxx[now]=a[l]; else lmax[now]=rmax[now]=0,maxx[now]=a[l]; } else { build(l,mid-1,mid); build(mid+1,r,mid); } v[now]=a[mid]; fa[now]=last; pushup(now); tr[last][mid>=f]=now; } inline void insert(int k,int tot){ for(int i=1;i<=tot;i++) scanf("%d",&a[i]); for(int i=1;i<=tot;i++) if(!q.empty()) id[i]=q.front(),q.pop(); else id[i]=++cnt; build(1,tot,0); int z=id[(1+tot)>>1]; int x=find(root,k+1),y=find(root,k+2); splay(x,root); splay(y,tr[x][1]); fa[z]=y; tr[y][0]=z; pushup(y); pushup(x); } inline void dfs(int x){ pushdown(x); if(tr[x][0]) dfs(tr[x][0]); printf("%d ",v[x]); if(tr[x][1]) dfs(tr[x][1]); } int main(){ freopen("seq2005.in","r",stdin); freopen("seq2005.out","w",stdout); int m; scanf("%d %d",&n,&m); maxx[0]=a[1]=a[n+2]=-INF; for(int i=1;i<=n;i++) scanf("%d",&a[i+1]); for(int i=1;i<=n+2;i++) id[i]=i; build(1,n+2,0); root=(n+3)>>1; cnt=n+2; int k,tot,val; while(m--){ cin>>s; if(s[0]!='M'||s[2]!='X') scanf("%d %d",&k,&tot); if(s[0]=='I') insert(k,tot); if(s[0]=='D') del(k,tot); if(s[0]=='M'){ if(s[2]=='X') printf("%d\n",maxx[root]); else scanf("%d",&val),modify(k,tot,val); } if(s[0]=='R') rev(k,tot); if(s[0]=='G') Sum(k,tot); //dfs(root); //printf("\n"); } return 0; }