NOI2005 维修数列(综合包括求区间的最大值)---Splay
2015-05-31 09:50
435 查看
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <string.h> #include <queue> #define N 500010 //数组要定大点 #define inf 1<<30 using namespace std; int pre , key , ch [2], root, tot, rev , same , size , sum1 ; //rev表示旋转标记,same表示数值改变的标记 int n, m, max1, s1, a , lmax , rmax , mmax , s , tot2; //lmax指从左边开始最大值, mmax指这个区间连续的最大值, 数组s用来回收空间 /* 区间最大和,可能是左子树的最大和,右子树的最大和,左子树的右端+节点+右子树的左端 伸展树里的节点所表示的树可以看做是一个区间,最左边和最右边分别是区间的两个端点 */ void update(int x) { int j=ch[x][0], k=ch[x][1]; size[x]=size[j]+size[k]+1; sum1[x]=sum1[j]+sum1[k]+key[x]; lmax[x]=max(lmax[j], sum1[j]+key[x]+max(0, lmax[k])); //在这个区间内 rmax[x]=max(rmax[k], sum1[k]+key[x]+max(0, rmax[j])); mmax[x]=max(0, rmax[j])+key[x]+max(0, lmax[k]); mmax[x]=max(mmax[x], max(mmax[j], mmax[k])); return ; } void updaterev(int x) //先处理x节点,rev[x]为1表示这个节点已经处理了(旋转) { if(!x)return ; swap(ch[x][0], ch[x][1]); swap(lmax[x], rmax[x]); //翻转时左右区间也交换! rev[x]^=1; return ; } void updatesame(int x, int k) { if(!x)return ; key[x]=k; sum1[x]=size[x]*k; lmax[x]=rmax[x]=mmax[x]=max(k, k*size[x]); //判断正负的最大值 same[x]=1; return ; } void pushdown(int x) { if(rev[x]) { updaterev(ch[x][0]); updaterev(ch[x][1]); rev[x]=0; } if(same[x]) { updatesame(ch[x][0], key[x]); updatesame(ch[x][1], key[x]); same[x]=0; } return ; } void newnode(int &r, int father, int k) { if(tot2) //用数组s回收来的空间新建,否则会TLE r=s[tot2--]; else r=++tot; pre[r]=father; size[r]=1; same[r]=rev[r]=0; ch[r][0]=ch[r][1]=0; key[r]=lmax[r]=rmax[r]=mmax[r]=sum1[r]=k; return ; } void build(int l, int r, int &k, int father) { if(l>r)return ; int mid=(l+r)>>1; newnode(k, father, a[mid]); build(l, mid-1, ch[k][0], k); build(mid+1, r, ch[k][1], k); update(k); return ; } void init() { pre[0]=rev[0]=same[0]=key[0]=ch[0][0]=ch[0][1]=root=tot=tot2=size[0]=0; lmax[0]=rmax[0]=mmax[0]=-inf; //这里要注意初始化 newnode(root, 0, -1); newnode(ch[root][1], root, -1); update(root); build(1, n, ch[ch[root][1]][0], ch[root][1]); update(ch[root][1]); update(root); return ; } void rotate(int x, int kind) { int k=pre[x]; pushdown(k); pushdown(x); ch[k][!kind]=ch[x][kind]; pre[ch[x][kind]]=k; ch[x][kind]=k; if(pre[k]) ch[pre[k]][ch[pre[k]][1]==k]=x; pre[x]=pre[k]; pre[k]=x; update(k); return ; } void Splay(int x, int goal) { int k, g, h; pushdown(x); while(pre[x]!=goal) { k=pre[x]; if(pre[k]==goal) { rotate(x, ch[k][0]==x); } else { g=(ch[k][0]==x?0:1); h=(ch[pre[k]][0]==k?0:1); if(g==h) { rotate(k, !g); rotate(x, !g); } else { rotate(x, !g); rotate(x, g); } } } if(!goal)root=x; update(x); return ; } int select(int k, int x) { pushdown(x); if(size[ch[x][0]]+1==k) return x; else if(size[ch[x][0]]+1>k) return select(k, ch[x][0]); else return select(k-size[ch[x][0]]-1, ch[x][1]); } int getmin(int r) { int s=r; pushdown(r); while(r) { s=r; r=ch[r][0]; pushdown(r); } return s; } void insert(int k, int num) { int j, g; j=select(k+1, root); Splay(j, 0); g=getmin(ch[root][1]); Splay(g, root); build(1, num, ch[g][0], g); update(g); update(j); return ; } void erase(int r) //回收空间 { if(!r)return ; s[++tot2]=r; erase(ch[r][0]); erase(ch[r][1]); return ; } void dele(int k, int num) { int j, g; j=select(k, root); g=select(k+num+1, root); Splay(j, 0); Splay(g, root); erase(ch[g][0]); pre[ch[g][0]]=0; ch[g][0]=0; update(g); update(j); return ; } void change(int k, int num, int c) { int j, g; j=select(k, root); g=select(k+num+1, root); Splay(j, 0); Splay(g, root); updatesame(ch[g][0], c); //这里是updatesame,对ch[g][0]处理 update(g); //更新 update(j); return ; } void reversal(int k, int num) { int j, g; j=select(k, root); g=select(k+num+1, root); Splay(j, 0); Splay(g, root); updaterev(ch[g][0]); return ; } int getsum(int k, int num) { int j, g; j=select(k, root); g=select(k+num+1, root); Splay(j, 0); Splay(g, root); return sum1[ch[g][0]]; } int getmax(int r) { int s=r; pushdown(r); while(r) { s=r; r=ch[r][1]; pushdown(r); } return s; } int maxsum() { int j, g; j=getmin(root); g=getmax(root); Splay(j, 0); Splay(g, root); return mmax[ch[g][0]]; } int main() { int t, j, k, g; char p[20]; while(scanf("%d%d", &n, &m)!=EOF) { for(t=1; t<=n; ++t) scanf("%d", a+t); init(); while(m--) { scanf("%s", p); if(strcmp(p, "INSERT")==0) { scanf("%d%d", &j, &k); for(t=1; t<=k; ++t) scanf("%d", a+t); insert(j, k); continue; } if(strcmp(p, "DELETE")==0) { scanf("%d%d", &j, &k); dele(j, k); continue; } if(strcmp(p, "MAKE-SAME")==0) { scanf("%d%d%d", &j, &k, &g); change(j, k, g); continue; } if(strcmp(p, "REVERSE")==0) { scanf("%d%d", &j, &k); reversal(j, k); continue; } if(strcmp(p, "GET-SUM")==0) { scanf("%d%d", &j, &k); printf("%d\n", getsum(j, k)); continue; } if(strcmp(p, "MAX-SUM")==0) { printf("%d\n", maxsum()); } } } return 0; }
相关文章推荐
- PostgreSQL function里面调用function
- hdu3487 (splay伸展树 区间翻转,切割,插入)
- Combination Sum
- Android TextView里直接显示图片的三种方法
- HTML 表单(form) 使用详解
- Redhat6.2升级为Redhat6.3 (linux内核升级)
- 回调函数理解-以Fragment为例
- Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)
- NOI2004 郁闷的出纳员
- Java web基础总结十之—— jsp EL表达式
- OpenGL_ES加载TGA/BMP纹理
- hdu4217 Data Structure?
- 【Android】工程中文件的关联性
- [转]动态规划解最长公共子序列问题
- Linux下whereis和which的区别
- percona-toolkit-2.2.14-1安装时Header V4 DSA/SHA1 Signature, key ID cd2efd2a: NOKEY
- 工厂模式
- 让一类只能产生一个实例对象
- 全屏slider--swiper
- 面试题之final,finally和finalize的区别以及如果catch里面有return语句,请问finally里面的代码还会执行吗?