【例题】【Splay】NKOJ2504 区间翻转问题
来源:互联网 发布:大疆无人机 知乎 编辑:程序博客网 时间:2024/03/29 21:12
NKOJ2504 区间翻转问题
时间限制 : 10000 MS 空间限制 : 265000 KB
问题描述
给你一个长度为N的序列{ai}和M个操作
1.查询第k个数的值
2.将第k个数增加d
3.查询一段区间的和
4.查询一段区间的最大值
5.将一段区间镜面翻转(例如序列{1,2,3,4,5,6},将从2到5的区间翻转后得到序列{1,5,4,3,2,6})
对于除操作2,5以外的操作,输出相应的答案
输入格式
第一行两个正整数N,M
第二行N个整数,为初始的序列
第三行到底M+2行,每行若干个整数
·如果第一个数为1,那么后面一个正整数k,表示查询第k个数的值
·如果第一个数是2,那么后面两个正整数k,d,表示将ak增加d
·如果第一个数为3,那么后面两个正整数l,r,表示查询从al到ar的区间和
·如果第一个数为4,那么后面两个正整数l,r,表示查询从al到ar的最大值
·如果第一个数为5,那么后面两个正整数l,r,表示翻转从al到ar的这个区间
输出格式
除操作2,5外每个操作输出占一行,一个整数,为本次提问的答案
样例输入
6 8
1 2 3 4 5 6
1 4
3 2 5
4 2 2
5 2 5
3 1 3
5 2 5
2 5 1
4 1 6
样例输出
4
14
2
10
6
提示
2<=N<=100000
1<=M<=100000
原序列1<=ai<=1000
每次1<=k<=N,1<=l<=r<=N,1<=d<=1000
来源 感谢nodgd命题并提供数据
思路:
维护下标,将每个数的下标存入树中。
(1)、查询第k个数:直接找
(2)、第k个数增加d:直接加
(3)、维护区间和。操作时将x-1为根、y+1为右儿子,则y+1左儿子的sum即为所求
(4)、维护区间最大。操作同(3)
(5)、lazy标记。操作同(3),再将y+1左儿子打标记
(3)、(4)、(5)注意覆盖1或n的情况特殊处理
#include<cstdio>#include<iostream>using namespace std;const int need=100005;int a[need];//.............................................inline void in_(int &d){ char t=getchar();bool mark=0; while(t<'0'||t>'9') {if(t=='-') mark=1;t=getchar();} for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';if(mark) d=-d;}inline void out_(int x){ if(x<0) {x=-x;putchar('-');} if(x>=10) out_(x/10); putchar(x%10+'0');}//.............................................int tot,root;int fa[need],ls[need],rs[need],si[need],num[need],sum[need],mm[need];bool lazy[need];inline void putdown(int x){ lazy[x]=0; swap(ls[x],rs[x]); if(ls[x]) lazy[ls[x]]^=1; if(rs[x]) lazy[rs[x]]^=1;} inline void NBHB(int x){ si[x]=si[ls[x]]+si[rs[x]]+1; sum[x]=sum[ls[x]]+sum[rs[x]]+a[num[x]]; mm[x]=max(a[num[x]],max(mm[ls[x]],mm[rs[x]]));}inline void sr(int x){ int y=fa[x],z=fa[y]; if(lazy[z]) putdown(z); if(lazy[y]) putdown(y); if(lazy[x]) putdown(x); ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z; ls[y]=rs[x]; fa[rs[x]]=y; rs[x]=y; fa[y]=x; NBHB(y),NBHB(x);}inline void sl(int x){ int y=fa[x],z=fa[y]; if(lazy[z]) putdown(z); if(lazy[y]) putdown(y); if(lazy[x]) putdown(x); ls[z]==y ? ls[z]=x :rs[z]=x; fa[x]=z; rs[y]=ls[x]; fa[ls[x]]=y; ls[x]=y; fa[y]=x; NBHB(y),NBHB(x);}int top,s[need];void splay(int x){ top=0;s[++top]=x; for(int i=x;fa[i];i=fa[i]) s[++top]=fa[i]; while(top) { if(lazy[s[top]]) putdown(s[top]); top--; } int y; while(y=fa[x]) { if(ls[y]==x) sr(x); else sl(x); } root=x;}void insert(int d) //不用putdown,因为先建树,再操作{ if(tot==0) { num[root=tot=1]=d; sum[1]=mm[1]=a[d]; si[1]=1; ls[1]=rs[1]=fa[1]=0; return ; } tot++; int p=root; while(true) { si[p]++; sum[p]+=a[d]; mm[p]=max(mm[p],a[d]); if(d<num[p]) if(ls[p]) p=ls[p]; else{ls[p]=tot;break;} else if(rs[p]) p=rs[p]; else{rs[p]=tot;break;} } si[tot]=1,sum[tot]=a[tot],fa[tot]=p,mm[tot]=a[d],num[tot]=d; splay(tot);}//.............................................int k,d,l,r;int getk(int k){ int p=root; while(true) { if(lazy[p]) putdown(p); if(ls[p]&&si[ls[p]]>=k) p=ls[p]; else if(k==1||(ls[p]&&si[ls[p]]==k-1)) return p; else {k-=si[ls[p]]+1;p=rs[p];} }}void change(int xx){ int y; while(fa[xx]!=root) { y=fa[xx]; if(lazy[y]) putdown(y); if(lazy[xx]) putdown(xx); if(ls[y]==xx) sr(xx); else sl(xx); }}int get(){ if(l>1&&r<tot) { int a=getk(l-1),b=getk(r+1); splay(a); change(b); return ls[b]; } else if(l>1&&r==tot) { int a=getk(l-1); splay(a); return rs[a]; } else if(l==1&&r<tot) { int b=getk(r+1); splay(b); return ls[b]; } else return root;}//.............................................int main(){ int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) in_(a[i]),insert(i); for(int i=1,b,kk;i<=m;i++) { in_(b); if(b==1) { in_(k); out_(a[num[getk(k)]]),putchar(10); } else if(b==2) { in_(k),in_(b); kk=num[getk(k)]; a[kk]+=b; splay(kk); } else { in_(l),in_(r); kk=get(); if(b==3) out_(sum[kk]),putchar(10); else if(b==4) out_(mm[kk]),putchar(10); else lazy[kk]^=1; } }}
- 【例题】【Splay】NKOJ2504 区间翻转问题
- 区间翻转问题 Splay
- Splay解决区间问题[区间切割,区间翻转]
- Splay区间翻转
- splay处理区间翻转例题【BZOJ 3223】 Tyvj 1729 文艺平衡树
- hdu 1890 splay区间翻转
- Splay tree 区间翻转 模板
- HDU 1890 splay区间翻转
- HDU 1890 Splay区间翻转
- hdu 1890 splay 区间翻转
- 【codevs 3303】翻转区间 splay
- BZOJ 3223 Splay区间翻转
- HDU3487(splay区间翻转+区间切割)
- hdu 1890 Splay区间最小值、区间翻转
- hdu 3487 区间 翻转 切割 插入 splay
- 【HDU】1890 Robotic Sort 翻转区间【splay】
- 11922 - Permutation Transformer (Splay区间翻转)
- HDU 3487 splay区间翻转切割
- 二叉树整理(三)
- Android状态栏微技巧,带你真正理解沉浸式模式
- 指针小结
- 微软认知服务 人脸识别 API 之 发现
- 20161203
- 【例题】【Splay】NKOJ2504 区间翻转问题
- setTimeout 深入分析其机制
- java获取文件夹下所有文件
- Android TextView文字横向自动滚动(跑马灯)
- 作用域和 this
- 类加载器学习
- raw格式(裸数据)格式文件读写
- VHDL TestBench数据产生方式
- c++中浮点数的存储方式