NOI2005维护数列 伸展树splay
来源:互联网 发布:鲍里斯三世知乎 编辑:程序博客网 时间:2024/05/21 14:52
7K的代码....从中午调到现在...终于调过去了.....太感动了.....
中文的题目题意就不多说了...前五个操作都是最基本的splay操作,最后一个稍微麻烦点,可以先去做做http://blog.csdn.net/yanglei040/article/details/12625039这个题..要求某个区间的最大子段和的话,对于每个区间,要维护区间和sum,区间最大后缀suff,最大前缀pref,最大子段和sub四个值,因为在pushup的时候,sub可以是他两个子区间的sub的最大值,也可能是左孩子的suff+自己的值+右孩子的pref,前缀和后缀的更新方式也基本类似了,然后...就没有然后了..慢慢调吧,耐心调早晚能调出来的...另外有一点要注意的就是make-same操作要用两个值维护,setn表示改成多少,same表示是否有标记。因为他的数据可能有make-same x y 0的情况,如果要用setn去表示是否标记的话,搞不好就要WA到哭了,我大部分时间都坑在这里了....先贴一个没加任何优化的代码..
#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=4000000+4000;int pre[maxn],ch[maxn][2];int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{ void pushup(int r) { if (r==0) return; size[r]=size[ch[r][0]]+1+size[ch[r][1]]; sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]]; pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]])); suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]])); sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]); sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]])); } void rotate(int x,int kind) { int y=pre[x]; pushdown(y); pushdown(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if (pre[y]) { ch[pre[y]][ch[pre[y]][1]==y]=x; } pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; pushup(y); pushup(x); } void splay(int x,int tgt) { pushdown(x); while(pre[x]!=tgt) { int y=pre[x]; pushdown(pre[y]); pushdown(y); pushdown(x); if (pre[pre[x]]==tgt) { rotate(x,ch[pre[x]][0]==x); } else { int kind=ch[pre[y]][0]==y; if (ch[y][kind]==x) { rotate(x,kind^1); rotate(x,kind); } else { rotate(y,kind); rotate(x,kind); } } } pushup(x); if (tgt==0) root=x; } void select(int k,int tgt) { int rt=root; pushdown(rt); while(true) { if (k<=size[ch[rt][0]]) rt=ch[rt][0]; else if (k==size[ch[rt][0]]+1) break; else k-=(size[ch[rt][0]]+1),rt=ch[rt][1]; pushdown(rt); } splay(rt,tgt); } void newnode(int &r,int father,ll k) { r=++tot; pre[r]=father; size[r]=1; flip[r]=setn[r]=0; key[r]=k; sum[r]=suff[r]=pref[r]=sub[r]=k; ch[r][0]=ch[r][1]=0; } void build(int l,int r,int &x,int rt) { if (l>r) return; int m=(l+r)>>1; newnode(x,rt,a[m]); build(l,m-1,ch[x][0],x); build(m+1,r,ch[x][1],x); pushup(x); } void init() { tot=root=0; newnode(root,0,-(1<<29)); newnode(ch[root][1],root,-(1<<29)); suff[0]=pref[0]=sub[0]=-(1<<29); suff[1]=pref[1]=sub[1]=-(1<<29); suff[2]=pref[2]=sub[2]=-(1<<29); build(1,n,ch[ch[root][1]][0],ch[root][1]); pushup(ch[root][1]); pushup(root); } void go_f(int r) { if(!r) return; flip[r]^=1; swap(ch[r][0],ch[r][1]); swap(suff[r],pref[r]); } void go_s(int r,ll c) { if (!r) return ; same[r]=true; key[r]=c; setn[r]=c; sum[r]=(ll)(size[r]*c); suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c); } void pushdownset(int r) { if (same[r]) { go_s(ch[r][0],setn[r]); go_s(ch[r][1],setn[r]); same[r]=false;// flip[r]=0; } } void pushdownflip(int r) { if (flip[r]) { go_f(ch[r][0]); go_f(ch[r][1]); flip[r]=0; } } void pushdown(int r) { pushdownset(r); pushdownflip(r); } void insert(int posi,int num) { ll c; select(posi+1,0); select(posi+2,root); scanf("%I64d",&c); newnode(ch[ch[root][1]][0],ch[root][1],c); int rt=ch[ch[root][1]][0]; for(int i=2; i<=num; i++) { scanf("%I64d",&c); newnode(ch[rt][1],rt,c); rt=ch[rt][1]; } while(pre[rt]) { rt=pre[rt]; pushup(rt); } pushup(root); } void del(int posi,int num) { select(posi,0); select(posi+num+1,root); int k=ch[ch[root][1]][0]; pre[k]=0; ch[ch[root][1]][0]=0; pushup(ch[root][1]); pushup(root); } void set_num(int posi,int num,ll c) { select(posi,0); select(posi+num+1,root); go_s(ch[ch[root][1]][0],c); pushup(ch[root][1]); pushup(root); int k=ch[ch[root][1]][0];// splay(k,0); } void reverse(int posi,int num) { select(posi,0); select(posi+num+1,root); go_f(ch[ch[root][1]][0]); int k=ch[ch[root][1]][0];// splay(k,0); } ll Sum(int posi,int num) { select(posi,0); select(posi+num+1,root); return sum[ch[ch[root][1]][0]]; } ll Max_sum() { splay(1,0); splay(2,root); return sub[ch[ch[root][1]][0]]; }}spt;char cmd[30];int x,y,z;ll c;int main(){ freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%I64d",&a[i]); spt.init(); getchar(); for (int i=1; i<=m; i++) {// cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n"; scanf("%s",cmd); if (cmd[0]=='G') { scanf("%d%d",&x,&y); printf("%I64d\n",spt.Sum(x,y)); } else if (cmd[0]=='I') { scanf("%d%d",&x,&y); spt.insert(x,y); } else if (cmd[0]=='M' && cmd[2]=='K') { scanf("%d%d%I64d",&x,&y,&c); spt.set_num(x,y,c); } else if (cmd[0]=='R') { scanf("%d%d",&x,&y); spt.reverse(x,y); } else if (cmd[0]=='M' && cmd[2]=='X') { printf("%I64d\n",spt.Max_sum()); } else if (cmd[0]=='D') { scanf("%d%d",&x,&y); spt.del(x,y); } } return 0;}
可以发现..时间跟内存的消耗都是惊人的...因为我直接开了400W的数组....而且insert操作的时候我是直接用while循环,插成了一条链,这样在以后旋转的时候,时间消耗会很大。题目里保证了数列里最大只有50W个数,也就是说,根本没必要开400W的数组,delete的时候,把空间回收再利用的话,50W的数组就够用了。参考了一下各路大神的代码,加上了内存回收,并且在insert的时候,直接插成一颗平衡树,时间和空间都会大大缩小。
#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=500000+5000;int pre[maxn],ch[maxn][2];int stk[maxn];int top;int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{ void pushup(int r) { if (r==0) return; size[r]=size[ch[r][0]]+1+size[ch[r][1]]; sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]]; pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]])); suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]])); sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]); sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]])); } void rotate(int x,int kind) { int y=pre[x]; pushdown(y); pushdown(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if (pre[y]) { ch[pre[y]][ch[pre[y]][1]==y]=x; } pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; pushup(y); pushup(x); } void splay(int x,int tgt) { pushdown(x); while(pre[x]!=tgt) { int y=pre[x]; pushdown(pre[y]); pushdown(y); pushdown(x); if (pre[pre[x]]==tgt) { rotate(x,ch[pre[x]][0]==x); } else { int kind=ch[pre[y]][0]==y; if (ch[y][kind]==x) { rotate(x,kind^1); rotate(x,kind); } else { rotate(y,kind); rotate(x,kind); } } } pushup(x); if (tgt==0) root=x; } void select(int k,int tgt) { int rt=root; pushdown(rt); while(true) { if (k<=size[ch[rt][0]]) rt=ch[rt][0]; else if (k==size[ch[rt][0]]+1) break; else k-=(size[ch[rt][0]]+1),rt=ch[rt][1]; pushdown(rt); } splay(rt,tgt); } void newnode(int &r,int father,ll k) { if (top) { r=stk[top--]; } else r=++tot; pre[r]=father; size[r]=1; flip[r]=setn[r]=0; same[r]=0; key[r]=k; sum[r]=suff[r]=pref[r]=sub[r]=k; ch[r][0]=ch[r][1]=0; } void build(int l,int r,int &x,int rt) { if (l>r) return; int m=(l+r)>>1; newnode(x,rt,a[m]); build(l,m-1,ch[x][0],x); build(m+1,r,ch[x][1],x); pushup(x); } void init() { tot=root=0; top=0; newnode(root,0,-(1<<29)); newnode(ch[root][1],root,-(1<<29)); suff[0]=pref[0]=sub[0]=-(1<<29); suff[1]=pref[1]=sub[1]=-(1<<29); suff[2]=pref[2]=sub[2]=-(1<<29); build(1,n,ch[ch[root][1]][0],ch[root][1]); pushup(ch[root][1]); pushup(root); } void go_f(int r) { if(!r) return; flip[r]^=1; swap(ch[r][0],ch[r][1]); swap(suff[r],pref[r]); } void go_s(int r,ll c) { if (!r) return ; same[r]=true; key[r]=c; setn[r]=c; sum[r]=(ll)(size[r]*c); suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c); } void pushdownset(int r) { if (same[r]) { go_s(ch[r][0],setn[r]); go_s(ch[r][1],setn[r]); same[r]=false;// flip[r]=0; } } void pushdownflip(int r) { if (flip[r]) { go_f(ch[r][0]); go_f(ch[r][1]); flip[r]=0; } } void pushdown(int r) { pushdownset(r); pushdownflip(r); } void insert(int posi,int num) { ll c; select(posi+1,0); select(posi+2,root); for (int i=1; i<=num; i++) scanf("%I64d",&a[i]); build(1,num,ch[ch[root][1]][0],ch[root][1]); } void del(int posi,int num) { select(posi,0); select(posi+num+1,root); int k=ch[ch[root][1]][0]; recover(k); pre[k]=0; ch[ch[root][1]][0]=0; pushup(ch[root][1]); pushup(root); } void set_num(int posi,int num,ll c) { select(posi,0); select(posi+num+1,root); go_s(ch[ch[root][1]][0],c); pushup(ch[root][1]); pushup(root); int k=ch[ch[root][1]][0];// splay(k,0); } void reverse(int posi,int num) { select(posi,0); select(posi+num+1,root); go_f(ch[ch[root][1]][0]); int k=ch[ch[root][1]][0];// splay(k,0); } ll Sum(int posi,int num) { select(posi,0); select(posi+num+1,root); return sum[ch[ch[root][1]][0]]; } ll Max_sum() { splay(1,0); splay(2,root); return sub[ch[ch[root][1]][0]]; } void recover(int r) { if (!r) return; stk[++top]=r; recover(ch[r][0]); recover(ch[r][1]); }}spt;char cmd[30];int x,y,z;ll c;int main(){ freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%I64d",&a[i]); spt.init(); getchar(); for (int i=1; i<=m; i++) {// cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n"; scanf("%s",cmd); if (cmd[0]=='G') { scanf("%d%d",&x,&y); printf("%I64d\n",spt.Sum(x,y)); } else if (cmd[0]=='I') { scanf("%d%d",&x,&y); spt.insert(x,y); } else if (cmd[0]=='M' && cmd[2]=='K') { scanf("%d%d%I64d",&x,&y,&c); spt.set_num(x,y,c); } else if (cmd[0]=='R') { scanf("%d%d",&x,&y); spt.reverse(x,y); } else if (cmd[0]=='M' && cmd[2]=='X') { printf("%I64d\n",spt.Max_sum()); } else if (cmd[0]=='D') { scanf("%d%d",&x,&y); spt.del(x,y); } } return 0;}
BZOJ上交的代码:
#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=500000+5000;int pre[maxn],ch[maxn][2];int stk[maxn];int top;int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{ void pushup(int r) { if (r==0) return; size[r]=size[ch[r][0]]+1+size[ch[r][1]]; sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]]; pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]])); suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]])); sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]); sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]])); } void rotate(int x,int kind) { int y=pre[x]; pushdown(y); pushdown(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if (pre[y]) { ch[pre[y]][ch[pre[y]][1]==y]=x; } pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; pushup(y); pushup(x); } void splay(int x,int tgt) { pushdown(x); while(pre[x]!=tgt) { int y=pre[x]; pushdown(pre[y]); pushdown(y); pushdown(x); if (pre[pre[x]]==tgt) { rotate(x,ch[pre[x]][0]==x); } else { int kind=ch[pre[y]][0]==y; if (ch[y][kind]==x) { rotate(x,kind^1); rotate(x,kind); } else { rotate(y,kind); rotate(x,kind); } } } pushup(x); if (tgt==0) root=x; } void select(int k,int tgt) { int rt=root; pushdown(rt); while(true) { if (k<=size[ch[rt][0]]) rt=ch[rt][0]; else if (k==size[ch[rt][0]]+1) break; else k-=(size[ch[rt][0]]+1),rt=ch[rt][1]; pushdown(rt); } splay(rt,tgt); } void newnode(int &r,int father,ll k) { if (top) { r=stk[top--]; } else r=++tot; pre[r]=father; size[r]=1; flip[r]=setn[r]=0; same[r]=0; key[r]=k; sum[r]=suff[r]=pref[r]=sub[r]=k; ch[r][0]=ch[r][1]=0; } void build(int l,int r,int &x,int rt) { if (l>r) return; int m=(l+r)>>1; newnode(x,rt,a[m]); build(l,m-1,ch[x][0],x); build(m+1,r,ch[x][1],x); pushup(x); } void init() { tot=root=0; top=0; newnode(root,0,-(1<<29)); newnode(ch[root][1],root,-(1<<29)); suff[0]=pref[0]=sub[0]=-(1<<29); suff[1]=pref[1]=sub[1]=-(1<<29); suff[2]=pref[2]=sub[2]=-(1<<29); build(1,n,ch[ch[root][1]][0],ch[root][1]); pushup(ch[root][1]); pushup(root); } void go_f(int r) { if(!r) return; flip[r]^=1; swap(ch[r][0],ch[r][1]); swap(suff[r],pref[r]); } void go_s(int r,ll c) { if (!r) return ; same[r]=true; key[r]=c; setn[r]=c; sum[r]=(ll)(size[r]*c); suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c); } void pushdownset(int r) { if (same[r]) { go_s(ch[r][0],setn[r]); go_s(ch[r][1],setn[r]); same[r]=false;// flip[r]=0; } } void pushdownflip(int r) { if (flip[r]) { go_f(ch[r][0]); go_f(ch[r][1]); flip[r]=0; } } void pushdown(int r) { pushdownset(r); pushdownflip(r); } void insert(int posi,int num) { ll c; select(posi+1,0); select(posi+2,root); for (int i=1; i<=num; i++) scanf("%lld",&a[i]); build(1,num,ch[ch[root][1]][0],ch[root][1]); } void del(int posi,int num) { select(posi,0); select(posi+num+1,root); int k=ch[ch[root][1]][0]; recover(k); pre[k]=0; ch[ch[root][1]][0]=0; pushup(ch[root][1]); pushup(root); } void set_num(int posi,int num,ll c) { select(posi,0); select(posi+num+1,root); go_s(ch[ch[root][1]][0],c); pushup(ch[root][1]); pushup(root); int k=ch[ch[root][1]][0];// splay(k,0); } void reverse(int posi,int num) { select(posi,0); select(posi+num+1,root); go_f(ch[ch[root][1]][0]); int k=ch[ch[root][1]][0];// splay(k,0); } ll Sum(int posi,int num) { select(posi,0); select(posi+num+1,root); return sum[ch[ch[root][1]][0]]; } ll Max_sum() { splay(1,0); splay(2,root); return sub[ch[ch[root][1]][0]]; } void recover(int r) { if (!r) return; stk[++top]=r; recover(ch[r][0]); recover(ch[r][1]); }}spt;char cmd[30];int x,y,z;ll c;int main(){ scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%lld",&a[i]); spt.init(); getchar(); for (int i=1; i<=m; i++) {// cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n"; scanf("%s",cmd); if (cmd[0]=='G') { scanf("%d%d",&x,&y); printf("%lld\n",spt.Sum(x,y)); } else if (cmd[0]=='I') { scanf("%d%d",&x,&y); spt.insert(x,y); } else if (cmd[0]=='M' && cmd[2]=='K') { scanf("%d%d%lld",&x,&y,&c); spt.set_num(x,y,c); } else if (cmd[0]=='R') { scanf("%d%d",&x,&y); spt.reverse(x,y); } else if (cmd[0]=='M' && cmd[2]=='X') { printf("%lld\n",spt.Max_sum()); } else if (cmd[0]=='D') { scanf("%d%d",&x,&y); spt.del(x,y); } } return 0;}
- NOI2005维护数列 伸展树splay
- 【伸展树】【NOI2005】维护数列
- 【NOI2005】【splay】维护数列
- 【SPLAY】NOI2005 维护数列
- noi2005维护数列 splay
- Splay Tree(伸展树)[NOI2005]维修数列
- splay BZOJ1500 NOI2005 维护数列
- 【jzoj2413】【NOI2005】【维护数列】【splay】
- bsoj 2246 【NOI2005】维护数列(splay解法)
- CODEVS-1758-维护数列-NOI2005-splay
- BZOJ 1500([NOI2005]维修数列-Splay的数列维护)
- noi2005 维护序列。 splay
- NOI2005 维修数列(splay)
- [NOI2005]维修数列 (Splay)
- [Splay] NOI2005 维修数列
- NOI2005 维修数列 Splay
- 【noi2005】维护数列
- [NOI2005] 维护数列 sequence
- 求二叉树的高度(非递归) .----美团二面=----硬伤 当时没有答上来
- jQuery Ajax请求-jQuery.post(url, [data], [callback], [type])
- c语言排序算法 动画效果展示
- windows 下的hadoop的安装
- HDOJ 3586 Information Disturbing
- NOI2005维护数列 伸展树splay
- $(document).ready()方法和window.onload()方法
- Kali Linux Tools List
- C# DataTable,DataSet,IList,IEnumerable 互转扩展属性
- HPCC(High Performance Computing Challenge)的输出
- 在控制台(Console)环境下编译Windows GUI程序
- [Google] 给一个无限的数据流,问某个时刻的中位数 。1) 数据流是整数 2)数据流不是整数
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- java那些小事---java的四舍五入