伸展树(插入区间,修改区间,区间置数,区间反转,区间求和,连续最大和)BZOJ1500
2014-11-30 17:20
369 查看
1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit:64 MB
Submit: 6678 Solved: 2018
[Submit][Status]
Description
Input
输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。Sample Input
9 82 -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
-110
1
10
HINT
Source
splay区间插入删除,反转,求和就不说了,前几篇博客都有
区间修改:setv表示该区间是不是被修改过,修改的时候把区间key修改,往下pushdown的时候根据key修改即可
最大字段和:保存一个左边连续最大,右边连续最大,区间连续最大,想线段树一样就行更新
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> #define Key_value ch[ch[root][1]][0] using namespace std; const int maxn=500010; const int INF=1000000000; int a[maxn],N,M; int ch[maxn][2],pre[maxn],size[maxn],key[maxn],rev[maxn]; int sum[maxn],setv[maxn]; int root,tot1,tot2,s[maxn]; int lx[maxn],rx[maxn],mx[maxn]; void NewNode(int &r,int f,int val) { if(tot2)r=s[tot2--]; else r=++tot1; ch[r][0]=ch[r][1]=0; pre[r]=f; key[r]=val; rev[r]=setv[r]=0; sum[r]=val; size[r]=1; lx[r]=rx[r]=mx[r]=val; } void update_setv(int r,int c) { if(!r)return; setv[r]=1; key[r]=c; sum[r]=size[r]*c; lx[r]=rx[r]=mx[r]=max(c,c*size[r]); } void pushup(int r) { int lc=ch[r][0],rc=ch[r][1]; size[r]=size[lc]+size[rc]+1; sum[r]=sum[rc]+sum[lc]+key[r]; lx[r]=max(lx[lc],sum[lc]+key[r]+max(0,lx[rc])); rx[r]=max(rx[rc],sum[rc]+key[r]+max(0,rx[lc])); mx[r]=max(mx[lc],mx[rc]); mx[r]=max(mx[r],max(0,rx[lc])+key[r]+max(0,lx[rc])); } void update_rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); swap(lx[r],rx[r]); rev[r]^=1; } void pushdown(int r) { if(setv[r]) { update_setv(ch[r][0],key[r]); update_setv(ch[r][1],key[r]); setv[r]=0; } if(rev[r]) { update_rev(ch[r][0]); update_rev(ch[r][1]); rev[r]=0; } } void build(int &x,int l,int r,int f) { if(l>r)return ; int mid=(l+r)>>1; NewNode(x,f,a[mid]); build(ch[x][0],l,mid-1,x); build(ch[x][1],mid+1,r,x); pushup(x); } void init() { root=tot1=tot2=0; ch[root][0]=ch[root][1]=size[root]=key[root]=pre[root]=0; sum[root]=rev[root]=0;lx[root]=rx[root]=mx[root]=-INF; NewNode(root,0,-1); NewNode(ch[root][1],root,-1); build(Key_value,1,N,ch[root][1]); pushup(ch[root][1]); pushup(root); } 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); } void Splay(int r,int goal) { pushdown(r); while(pre[r]!=goal) { if(pre[pre[r]]==goal) { pushdown(pre[r]); pushdown(r); Rotate(r,ch[pre[r]][0]==r); } else { pushdown(pre[pre[r]]); pushdown(pre[r]); pushdown(r); int y=pre[r]; int kind=(ch[pre[y]][0]==y); if(ch[y][kind]==r) { Rotate(r,!kind); Rotate(r,kind); } else { Rotate(y,kind); Rotate(r,kind); } } } pushup(r); if(goal==0)root=r; } int get_kth(int r,int k) { pushdown(r); int t=size[ch[r][0]]+1; if(t==k)return r; if(t>k)return get_kth(ch[r][0],k); else return get_kth(ch[r][1],k-t); } void Insert(int pos,int tot) { Splay(get_kth(root,pos+1),0); Splay(get_kth(root,pos+2),root); build(Key_value,1,tot,ch[root][1]); pushup(ch[root][1]); pushup(root); } void erase(int r) { if(r) { s[++tot2]=r; erase(ch[r][0]); erase(ch[r][1]); } } void Delete(int pos,int tot) { Splay(get_kth(root,pos),0); Splay(get_kth(root,pos+1+tot),root); erase(Key_value); pre[Key_value]=0; Key_value=0; pushup(ch[root][1]); pushup(root); } void MakeSame(int pos,int tot,int c) { Splay(get_kth(root,pos),0); Splay(get_kth(root,pos+1+tot),root); update_setv(Key_value,c); pushup(ch[root][1]); pushup(root); } void Reverse(int pos,int tot) { Splay(get_kth(root,pos),0); Splay(get_kth(root,pos+1+tot),root); update_rev(Key_value); pushup(ch[root][1]); pushup(root); } void GetSum(int pos,int tot) { Splay(get_kth(root,pos),0); Splay(get_kth(root,pos+1+tot),root); pushup(ch[root][1]); pushup(root); printf("%d\n",sum[Key_value]); } void MaxSum(int pos,int tot) { Splay(get_kth(root,pos),0); Splay(get_kth(root,pos+1+tot),root); printf("%d\n",mx[Key_value]); } int main() { char op[20]; int pos,tot,c; while(scanf("%d%d",&N,&M)!=EOF) { for(int i=1;i<=N;i++)scanf("%d",&a[i]); init(); while(M--) { scanf("%s",op); if(op[0]=='I') { scanf("%d%d",&pos,&tot); for(int i=1;i<=tot;i++) scanf("%d",&a[i]); Insert(pos,tot); } else if(op[0]=='D') { scanf("%d%d",&pos,&tot); Delete(pos,tot); } else if(!strcmp(op,"MAKE-SAME")) { scanf("%d%d%d",&pos,&tot,&c); MakeSame(pos,tot,c); } else if(op[0]=='R') { scanf("%d%d",&pos,&tot); Reverse(pos,tot); } else if(op[0]=='G') { scanf("%d%d",&pos,&tot); GetSum(pos,tot); } else MaxSum(1,size[root]-2); } } return 0; }
相关文章推荐
- [NOI2005]维修数列 Splay tree 区间反转,修改,求和,求最值
- 【树状数组】【单点修改区间求和】【区间修改单点查询】【单点修改区间最大值查询】
- 伸展树(区间加值,反转,循环移动,插入,删除区间,求区间最小值)poj3580
- spoj 1716...动态区间的最大连续子段和问题...点修改...
- 伸展树(插入、删除区间)BZOJ1269
- bzoj 1500 修改区间 splay
- bzoj 1012 BST 支持插入,区间最大
- bzoj1500 修改数列 区间splay树讲解
- poj 3667 线段树成端更新区间最大连续和
- 线段树的应用(最大值,区间求和)
- 求和最大的连续子串
- 区间插入求和 — 线段树入门(二)
- 线段树之成段更新(区间最大连续和)
- PKU2892(Tunnel Warfare)线段树求最大连续区间
- BZOJ 3110([Zjoi2013]K大数查询-区间第k大[段修改,在线]-树状数组套函数式线段树)
- 求和最大的连续子串
- 贪心算法-求区间至少连续k的最大和
- spoj 1557 线段树 区间最大连续和 (不重复数)
- 【贪心\最大连续区间和】游览路线
- 单调队列的一个应用——求解连续区间最大值(HDU Max Sum of Max-K-sub-sequence)