数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列

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 }
时间: 2024-07-31 02:03:06

数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列的相关文章

NOI2005维护数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 1879[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

[模板]洛谷T2042 NOI2005 维护数列 Splay

PS:某大佬讲,当心情特别好or特别不好的时候,可以来攻略这个题...果然萌新足足被这题恶心了半个月... 进入正题: 这道题题意如此之裸-Splayの究极进化,那么就没有什么好讲的,直接说搞法好了... 为了代码写起来方便,萌新封装得可能有些过,若不合诸位大佬的口味还请见谅~ 节点node结构体定义: key:节点原值:size:子树大小:ch[2]:子树指针: set_pd:记录是否打了MAKE-SAME的懒标记:setv:MAKE-SAME的修改值:turn:记录是否旋转: sum:子树元

[BZOJ1500]NOI2005 维护数列|splay

这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛..一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了..然后想了很久突然顿悟..貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛..(当时太弱) 然后我就一口气写了下来.. 对每个节点维护size,sum,maxsum,maxpre,maxpos(这两个用于更新maxsum),same,rev(这两个是lazy标

数据结构(Splay平衡树):HDU 1890 Robotic Sort

Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3456    Accepted Submission(s): 1493 Problem Description Somewhere deep in the Czech Technical University buildings, there are labora

BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

☆ [ZJOI2006] 书架 「平衡树维护数列」

题目类型:平衡树 传送门:>Here< 题意:要求维护一个数列,支持:将某个元素置顶或置底,交换某元素与其前驱或后继的位置,查询编号为\(S\)的元素的排名,查询排名第\(k\)的元素编号 解题思路 可以说是平衡树维护数列的入门题.当平衡树在维护数列时,关键字是在数列中的排名.因此中序遍历即为当前数列.注意在平衡树维护数列中,会涉及到两个编号.一个编号是这个节点在平衡树内的编号,一般外界是不会直接访问的.另一个是题目赋予的编号,代表这个位置数列上对应的值.外部编号即为一个附加值.当我们需要找到

【NOI2005】维护数列

描述 请写一个程序,要求维护一个数列,支持以下6种操作:(请注意,格式栏中的下划线' _ '表示实际输入文件中的空格) 格式 输入格式 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内.插入的数字总数不超过4 000 000个,输入文件大小不超过20MB

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++