bzoj 1500 [NOI 2005] 维修数列

题目大意不多说了

貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧

还是有很多操作的,估计够以后当模版了。。。。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6
  7 using namespace std;
  8 const int N = 1000010;
  9 const int INF = 0x3f3f3f3f;
 10 #define ls ch[x][0]
 11 #define rs ch[x][1]
 12
 13 struct SplayTree{
 14     int ch[N][2] , pre[N];
 15     int ml[N] , mr[N] , mm[N]; //区间最大
 16     int val[N] , sz[N] , sum[N] , size , rt;
 17     int rev[N] , to[N]; // lazy标记
 18     int del[N] , top; //内部保存删除的数的位置,然后可以从其中提取位置给新进入的元素
 19     int a[N];
 20
 21     void push_up(int x)
 22     {
 23         sz[x] = sz[ls]+sz[rs]+1;
 24         sum[x] = sum[ls]+sum[rs]+val[x];
 25         /*********************/
 26         ml[x] = max(ml[ls] , sum[ls]+val[x]+max(ml[rs] , 0));
 27         mr[x] = max(mr[rs] , sum[rs]+val[x]+max(mr[ls] , 0));
 28         mm[x] = max(mm[ls] , max(mm[rs] , max(ml[rs],0)+max(mr[ls],0)+val[x]));
 29         /*********************/
 30     }
 31
 32     void push_down(int x)
 33     {
 34         if(rev[x]){
 35             if(ls){
 36                 rev[ls]^=1 ;
 37                 swap(ml[ls] , mr[ls]);
 38             }
 39             if(rs){
 40                 rev[rs]^=1 ;
 41                 swap(ml[rs] , mr[rs]);
 42             }
 43             swap(ls , rs);
 44             rev[x] = 0;
 45         }
 46         /**to[x]的初始化要注意**/
 47         if(to[x]!=-INF){
 48             if(ls){
 49                 sum[ls] = sz[ls]*to[x];
 50                 ml[ls] = mr[ls] = mm[ls] = max(sum[ls] , to[x]);
 51                 val[ls] = to[ls] = to[x];
 52             }
 53             if(rs){
 54                 sum[rs] = sz[rs]*to[x];
 55                 ml[rs] = mr[rs] = mm[rs] = max(sum[rs] , to[x]);
 56                 val[rs] = to[rs] = to[x];
 57             }
 58             to[x] = -INF;
 59         }
 60     }
 61
 62     void newNode(int &x , int fa , int v)
 63     {
 64         if(top != -1)
 65             x = del[top--];
 66         else x = ++size;
 67         ch[x][0] = ch[x][1] = 0;
 68         pre[x] = fa;
 69         val[x] = v , sz[x] = 1;
 70         sum[x] = ml[x] = mr[x] = mm[x] = val[x];
 71         rev[x] = 0 , to[x] = -INF;
 72     }
 73
 74     void build(int &x , int l , int r , int fa)
 75     {
 76         if(l>r) return;
 77         int m=(l+r)>>1;
 78         newNode(x , fa , a[m]);
 79         build(ls , l , m-1 , x);
 80         build(rs , m+1 , r , x);
 81         push_up(x);
 82     }
 83
 84     void init(int n)
 85     {
 86         /*****因为所有点的最终叶子节点都下标设为了0,所以0上的数据要不影响整棵树*****/
 87         sz[0] = sum[0] = ch[0][0] = ch[0][1] = val[0] = pre[0] = 0;
 88         to[0] = ml[0] = mr[0] = mm[0] = -INF;
 89         rev[0] = 0;
 90         top = -1 , rt = size = 0;
 91         newNode(rt , 0 , -INF);
 92         newNode(ch[rt][1] , rt , -INF);
 93         build(ch[ch[rt][1]][0] , 1 , n , ch[rt][1]);
 94         push_up(ch[rt][1]);
 95         push_up(rt);
 96     }
 97
 98     void Rotate(int x , int f)
 99     {
100         int y=pre[x] , z=pre[y];
101         /**y要旋转到下方,下传lazy标记**/
102         push_down(y);
103         ch[y][!f] = ch[x][f] , pre[ch[x][f]] = y;
104         ch[x][f] = y , pre[y] = x;
105         ch[z][ch[z][1]==y] = x , pre[x]=z;
106         push_up(y);
107         push_up(x);
108     }
109
110     void Splay(int x , int goal)
111     {
112         while(pre[x] != goal){
113             if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0]==x);
114             else{
115                 int y = pre[x] , z = pre[y];
116                 int f = ch[z][0] == y;
117                 if(ch[y][f] == x) Rotate(x , !f);
118                 else Rotate(y,f);
119                 Rotate(x , f);
120             }
121         }
122         push_up(x);
123         if(goal == 0) rt = x;
124     }
125
126     int Select(int pos)
127     {
128         int x = rt;
129         push_down(x);
130         while(sz[ls]+1 != pos){
131             if(sz[ls]+1>pos) x=ls;
132             else{
133                 pos = pos-sz[ls]-1;
134                 x = rs;
135             }
136             push_down(x);
137         }
138         return x;
139     }
140     /***从pos位置之后插入cnt个值***/
141     void Insert(int pos , int cnt)
142     {
143         int x = Select(pos);
144         Splay(x , 0);
145         int y = Select(pos+1);
146         Splay(y , x);
147         build(ch[y][0] , 1 , cnt , y);
148         /***这里build将a[1~cnt]插入到splay树中,要push_up更新***/
149         push_up(y);
150         push_up(x);
151     }
152     /***回收被删除的数的位置***/
153     void Recycle(int x)
154     {
155         if(x){
156             del[++top]=x;
157             Recycle(ls);
158             Recycle(rs);
159         }
160     }
161
162     void Delete(int s , int t)
163     {
164         int x = Select(s-1) , y = Select(t+1);
165         Splay(x , 0) , Splay(y , x);
166         Recycle(ch[y][0]);
167         ch[y][0] = 0;
168         /***这里y的左子树删除,明显子树数据改变,所以要重新push_up更新数据***/
169         push_up(y);
170         push_up(x);
171     }
172     /****将s~t区间内的所有值都修改为v****/
173     void update(int s , int t , int v)
174     {
175         int x = Select(s-1) , y = Select(t+1);
176         Splay(x , 0) , Splay(y , x);
177         int ptr = ch[y][0];
178         to[ptr]=v;
179         val[ptr]=v;
180         sum[ptr]=v*sz[ptr];
181         ml[ptr] = mr[ptr] = mm[ptr] = max(sum[ptr] , v);
182         return ;
183     }
184
185     void Reverse(int s , int t)
186     {
187         int x = Select(s-1) , y = Select(t+1);
188         Splay(x , 0) , Splay(y , x);
189         int ptr = ch[y][0];
190         rev[ptr]^=1;
191         swap(ml[ptr] , mr[ptr]);
192     }
193
194     int querySum(int s , int t)
195     {
196         int x = Select(s-1) , y =  Select(t+1);
197        // cout<<"x: "<<x<<" y: "<<y<<endl;
198         Splay(x , 0) , Splay(y , x);
199         return sum[ch[y][0]];
200     }
201
202     int queryMax()
203     {
204         int x = Select(1) , y = Select(sz[rt]);
205         Splay(x , 0) , Splay(y , x);
206         return mm[ch[y][0]];
207     }
208 }spt;
209 int main()
210 {
211   //  freopen("a.in" , "r" , stdin);
212     int n , m;
213     char str[20] ;
214     int s , t , v , pos , k;
215     while(~scanf("%d%d" , &n , &m))
216     {
217         for(int i=1 ; i<=n ; i++) scanf("%d" , &spt.a[i]);
218         spt.init(n);
219         /*
220         for(int i=0 ; i<=spt.size ; i++){
221             cout<<"i: "<<i<<" sum: "<<spt.sum[i]<<" l: "<<spt.ch[i][0]<<" lv: "<<spt.val[spt.ch[i][0]]<<" r: "<<spt.ch[i][1]<<" rv: "<<spt.val[spt.ch[i][1]]<<endl;
222         }*/
223         for(int i=0 ; i<m ; i++){
224             scanf("%s" , str);
225             if(str[0] == ‘I‘){
226                 scanf("%d%d" , &pos , &k);
227                 for(int i=1 ; i<=k ; i++) scanf("%d" , &spt.a[i]);
228                 spt.Insert(pos+1 , k);
229             }
230             else if(str[0]==‘D‘){
231                 scanf("%d%d" , &pos , &k);
232                 spt.Delete(pos+1 , pos+k);
233             }
234             else if(str[0] == ‘M‘ && str[2] == ‘K‘){
235                 scanf("%d%d%d" , &pos , &k , &v);
236                 spt.update(pos+1 , pos+k , v);
237             }
238             else if(str[0] == ‘R‘){
239                 scanf("%d%d" , &pos , &k);
240                 spt.Reverse(pos+1 , pos+k);
241             }
242             else if(str[0] == ‘G‘){
243                 scanf("%d%d" , &pos , &k);
244                 printf("%d\n" , spt.querySum(pos+1 , pos+k));
245             }
246             else{
247                 /****这里不能直接用spt.mm[rt]作为答案,因为为了方便查询,
248                 我们增加了两个不包含在本身数组的点,直接spt.mm[rt]会把这两个点也算进来***/
249                 printf("%d\n" , spt.queryMax());
250             }
251         }
252     }
253     return 0;
254 }
时间: 2024-11-12 09:16:29

bzoj 1500 [NOI 2005] 维修数列的相关文章

BZOJ 1500 NOI 2005 维修数列 Splay

题意:见下图 传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好.. 这个题对Splay的所有操作基本是全了. 插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上. 删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉.(这里可以用数组优化,可以避免递归free节省时间) 修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换. 求和:维护

NOI 2005 维修数列

妈妈呀我终于过了!!!原来是数据坑我!!! 弃疗弃疗弃疗弃疗!!!!我调了一天呢....被GET_SUM 8 0打败了.... 啥也不说了....还是我太年轻.... 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<cstring> 7 #define PAU put

noi 2005维修数列

OI生涯中最想过的一题=v= splay加上各种各样的操作,样例又不敢拿来调了... 感觉指针写splay好难调,所以以后写splay都用数组吧(其实是因为黄大神也用数组orz) 好像是2小时敲完..debug了2天TAT一开始把操作6和某提混了... 然后搞来搞去才发现读入有个毛病0A0 再然后又发现一直以来自己的pushdown和别人是不一样的..(那些题我居然过了...) 最后被内存限制卡住,时间换空间..(然而本地测试90...难道是我的电脑太慢?) 虽然很累,但学了不少,值了 1 #i

NOI 2005维护数列

题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目. 第 2 行包含 N 个数字,描述初始时的数列. 以下 M 行,每行一条命令,格式参见问题描述中的表格 输出格式: 对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结 果,每个答案(数字)占一行. SOL: 我们发

BZOJ 1502 NOI 2005 月下柠檬树 计算几何 自适应辛普森积分

题目大意:有一个由圆锥和圆台组成的柠檬树,在月亮发出的平行光下,可以形成一个影子,求这个影子的面积. 思路:理解投影的性质:只要是平行光线,投影在水平面上,所得的图形都与原图形全等. 知道了这一点我们就可以画画图,分析就知道,其实柠檬树的影子,就是一些园和等腰梯形的面积的并.(如下图,样例) 运用计算几何的知识就可以得到圆的方程和圆的公切线的方程,然后得到一个连续的函数.最后这个题就成为一直函数的解析式,求这个函数与X轴之间的面积. 套用辛普森积分:Simpson(l,r) = (F(l) +

BZOJ 1500: [NOI2005]维修数列

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

【BZOJ】1500: [NOI2005]维修数列

[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=5e5+10,inf=0x3f3f3f3f; int n,m,root,a[maxn],t

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 ; ++

[代码] bzoj 1500 维修数列(无旋treap)

- 传送门 - http://www.lydsy.com/JudgeOnline/problem.php?id=1500 1500: [NOI2005]维修数列 Time Limit:?10 Sec??Memory Limit:?64 MB Submit:?15301??Solved:?5063 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行