bzoj 1500: [NOI2005]维修数列(splay)
来源:互联网 发布:东三环java培训 编辑:程序博客网 时间:2024/05/02 02:29
1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12283 Solved: 3884
[Submit][Status][Discuss]
Description
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
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
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
Sample Output
-1
10
1
10
10
1
10
HINT
Source
题解:splay
这道题其实好几个月前就尝试写过,不过当时并没有调出来,然后就弃疗了。
今天重新构思写的,不过还是写了接近4个小时T_T
思路很简单,关键是维护的值很多,有很多需要注意的细节。
注意事项如下:
1、make-same,注意cover数组的值不能为0,因为有可能将一段的值全部赋值成0,让cover在没有值得时候等于极大值即可。
2、mx数组用来存储子树中连续一段的最大值。注意这个变量的初值不能为0,应该是最小值,而且mx[0]=-inf。因为在没有左右子树的情况下会访问到0节点。那么mx数值表示的连续一段的长度不能为0,所以如果当前点为负值且没有左右子树,那么mx应该等于本身的值。
3、注意cover的时候只有有的子树才改变,否则将0节点改变了,会造成不必要的麻烦。
4、find第x个节点的时候要注意下方标记。
5、翻转的时候光交换左右儿子还不够,ls,rs也要对应交换(ls表示左边连续的最大值,rs表示右边连续的最大值,这两个值都可以是0)
6、需要写内存回收,否则会MLE
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<queue>#define N 1000003#define inf 1000000using namespace std;int ch[N][2],ls[N],rs[N],sum[N],cover[N],rev[N],key[N],size[N],f[N],mx[N];int n,m,a[N],cnt[N],tot,root;queue<int> p;void clear(int now){sum[now]=ls[now]=rs[now]=ch[now][0]=ch[now][1]=key[now]=size[now]=f[now]=rev[now]=0;mx[now]=-inf;cover[now]=inf;}void update(int now){ sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+key[now]; size[now]=size[ch[now][0]]+size[ch[now][1]]+1;ls[now]=max(ls[ch[now][0]],key[now]+sum[ch[now][0]]+ls[ch[now][1]]);rs[now]=max(rs[ch[now][1]],key[now]+sum[ch[now][1]]+rs[ch[now][0]]);mx[now]=max(max(mx[ch[now][0]],mx[ch[now][1]]),rs[ch[now][0]]+ls[ch[now][1]]+key[now]);}int get(int now){return ch[f[now]][1]==now; }void change(int now,int x){key[now]=x;sum[now]=x*size[now];if (x>=0) ls[now]=rs[now]=mx[now]=sum[now];else ls[now]=rs[now]=0,mx[now]=key[now];}void change1(int now){swap(ch[now][0],ch[now][1]);swap(ls[now],rs[now]);}void pushdown(int now){if (cover[now]!=inf) {if (ch[now][0]) change(ch[now][0],cover[now]),cover[ch[now][0]]=cover[now];if (ch[now][1]) change(ch[now][1],cover[now]),cover[ch[now][1]]=cover[now];cover[now]=inf;}if (rev[now]){change1(ch[now][0]); change1(ch[now][1]);rev[ch[now][0]]^=1; rev[ch[now][1]]^=1;rev[now]=0;}}void rotate(int x){int y=f[x]; int z=f[y];pushdown(y); pushdown(x); int which=get(x);ch[y][which]=ch[x][which^1]; f[ch[x][which^1]]=y;ch[x][which^1]=y; f[y]=x; f[x]=z;if (z) ch[z][ch[z][1]==y]=x;update(y); update(x);}void splay(int x,int tar){for (int fa;(fa=f[x])!=tar;rotate(x)) if (f[fa]!=tar) rotate(get(x)==get(fa)?fa:x);if (!tar) root=x;}int build(int l,int r,int fa){if (l>r) return 0;int now=cnt[++tot]; int mid=(l+r)/2;key[now]=a[mid]; f[now]=fa;if (l==r) {size[now]=1; cover[now]=inf;if (a[l]>=0) ls[now]=rs[now]=mx[now]=a[mid];else ls[now]=rs[now]=0,mx[now]=a[mid];sum[now]=a[mid];return now; }ch[now][0]=build(l,mid-1,now);ch[now][1]=build(mid+1,r,now);cover[now]=inf;update(now);return now;}void dfs(int now){if (!now) return;dfs(ch[now][1]); dfs(ch[now][0]);clear(now);p.push(now);}int find(int x){int now=root; while (true) { pushdown(now); if (x<=size[ch[now][0]]) now=ch[now][0]; else { x-=(size[ch[now][0]]+1); if (x==0) return now; now=ch[now][1]; } } return -1; }int main(){freopen("a.in","r",stdin);scanf("%d%d",&n,&m);a[1]=-1001;a[n+2]=-1001;mx[0]=-inf;for (int i=2;i<=n+1;i++) scanf("%d",&a[i]);for (int i=1;i<=1000000;i++) p.push(i);for (int i=1;i<=n+2;i++) cnt[i]=p.front(),p.pop();//for (int i=1;i<=n+2;i++) cout<<a[i]<<" ";//cout<<endl;root=build(1,n+2,0);for (int i=1;i<=m;i++) {char s[20]; scanf("%s",s+1);if (s[1]=='I') {int x,k; scanf("%d%d",&x,&k); tot=0;for (int j=1;j<=k;j++) scanf("%d",&a[j]),cnt[j]=p.front(),p.pop();int point=build(1,k,0);int aa=find(x+1); splay(aa,0); int bb=find(x+2); splay(bb,aa);ch[ch[root][1]][0]=point;f[point]=ch[root][1];update(ch[root][1]); update(root);}if (s[1]=='R') {int x,k; scanf("%d%d",&x,&k);k+=x-1;int aa=find(x); splay(aa,0);int bb=find(k+2); splay(bb,aa);int t=ch[ch[root][1]][0];swap(ch[t][0],ch[t][1]); swap(ls[t],rs[t]); rev[ch[ch[root][1]][0]]^=1;update(ch[root][1]); update(root);}if (s[1]=='G') {int x,k; scanf("%d%d",&x,&k);k+=x-1;int aa=find(x); splay(aa,0);int bb=find(k+2); splay(bb,aa);printf("%d\n",sum[ch[ch[root][1]][0]]);} if (s[1]=='M'&&s[3]=='K') { int x,k,c; scanf("%d%d%d",&x,&k,&c);k+=x-1;int aa=find(x); splay(aa,0);int bb=find(k+2); splay(bb,aa);int t=ch[ch[root][1]][0];cover[t]=c; change(t,c); update(ch[root][1]); update(root);}if (s[1]=='M'&&s[3]=='X') printf("%d\n",mx[root]);if (s[1]=='D') {int x,k; scanf("%d%d",&x,&k);k+=x-1;int aa=find(x); splay(aa,0);int bb=find(k+2); splay(bb,aa);int t=ch[ch[root][1]][0];dfs(t);ch[ch[root][1]][0]=0; update(ch[root][1]); update(root);}}}
0 0
- bzoj 1500: [NOI2005]维修数列(splay)
- [BZOJ 1500][NOI2005]维修数列(Splay)
- BZoj 1500 [NOI2005]维修数列 (Splay 模板)
- BZOJ 1500 NOI2005 维修数列 Splay
- 【BZOJ】1500 [NOI2005]维修数列 【splay】
- 【splay】BZOJ 1500: [NOI2005]维修数列
- bzoj 1500 NOI2005 维修数列 [Splay]
- BZOJ 1500 【NOI2005 D1T2】 维修数列 Splay
- BZOJ 1500: [NOI2005]维修数列 Splay
- BZOJ 1500 [NOI2005]维修数列 Splay
- BZOJ 1500: [NOI2005]维修数列 splay
- BZOJ 1500([NOI2005]维修数列-Splay的数列维护)
- 1500: [NOI2005]维修数列(Splay)
- NOI2005 维修数列(splay)
- [NOI2005]维修数列 (Splay)
- [Splay] NOI2005 维修数列
- NOI2005 维修数列 Splay
- 【BZOJ 1500】 [NOI2005]维修数列
- 94. Binary Tree Inorder Traversal
- 解决 Hadoop 集群执行包含 third-part lib 的 jar包的 ClassNotFoundException 问题
- Android入门——选择器selelctor之ColorStateList和StateListDrawable使用小结
- WebView shouldOverrideUrlLoading 方法使用
- 进程间通信方式以及各自的优缺点
- bzoj 1500: [NOI2005]维修数列(splay)
- apt-get指令
- linux进程调度 - 进程调度初始化与运行队列
- JSON数组对象和对象数组
- linux(red hat5版本为例)上jdk的安装
- uva 10118 Free Candy dp记忆化搜索
- C语言实现链表的创建,初始化,插入,删除,查找
- 正点原子标准例程-库函数版本——触摸按键扫描函数u8 TP_Scan(u8 tp)交流
- 动物乐园