BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 12278  Solved: 3880
[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

Sample Output

-1
10
1
10



太神了

splay维护序列

额外维护信息:rev翻转标记,tag修改标记,sum子树和,mx lm rm最大连续和那一套

update和paint和pushDown与线段树类似(修改之后翻转标记就可以忽略了)

build前注意

a[1]=a[n+2]=-INF;//防止计入mx中
t[0].mx=t[0].lm=t[0].rm=-INF;t[0].sum=0;

加入哨兵节点

「注意update和更新父子关系」

INSERT:提取区间k+1,k+2把新序列建树然后加到k+2.lc上

DELETE:提取k+1,k+1+tot 递归删除k+1+tot.lc每个节点

MAKE-SAME:提取 打标记

REVERSE:提取 打标记

GET-SUM:提取 sum

MAX-SUM:根.mx

注意要回收节点编号,所以用nw(),建树每个节点必须分配一个编号,不能直接用下标了

kth的时候pushDown过了,splay和update就不用了



1.仿照前人的做法写了一份

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long ll;
  8 #define lc t[x].ch[0]
  9 #define rc t[x].ch[1]
 10 #define pa t[x].fa
 11 const int N=5e5+5,INF=1e9;
 12 int read(){
 13     char c=getchar();int x=0,f=1;
 14     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1; c=getchar();}
 15     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘; c=getchar();}
 16     return x*f;
 17 }
 18 int n,m,a[N],pos,tot,v;
 19 char s[100];
 20 struct node{
 21     int ch[2],fa,size,v,rev,tag,sum,mx,lm,rm;
 22 }t[N];
 23 int cnt,root;
 24 inline int wh(int x){return t[pa].ch[1]==x;}
 25 int st[N],top=0;
 26 inline int nw(){
 27     int x;
 28     if(top) x=st[top--];else x=++cnt;
 29     lc=rc=pa=t[x].tag=t[x].rev=0;
 30     t[x].size=1;
 31     t[x].mx=t[x].sum=t[x].lm=t[x].rm=-INF;
 32     return x;r
 33 }
 34 inline void update(int x){
 35     t[x].size=t[lc].size+t[rc].size+1;
 36     t[x].sum=t[lc].sum+t[rc].sum+t[x].v;
 37     t[x].mx=max(max(t[lc].mx,t[rc].mx), max(0,t[lc].rm)+t[x].v+max(0,t[rc].lm));
 38     t[x].lm=max(t[lc].lm,t[lc].sum+t[x].v+max(0,t[rc].lm));
 39     t[x].rm=max(t[rc].rm,t[rc].sum+t[x].v+max(0,t[lc].rm));
 40 }
 41 inline void paint(int x){//reverse
 42     if(!x) return;
 43     t[x].rev^=1;
 44     swap(lc,rc);
 45     swap(t[x].lm,t[x].rm);
 46 }
 47 inline void paint(int x,int v){//make_same
 48     if(!x) return;
 49     t[x].v=v;t[x].sum=v*t[x].size;
 50     t[x].lm=t[x].rm=t[x].mx=max(v,t[x].sum);
 51     t[x].tag=1;t[x].rev=0;
 52 }
 53
 54 inline void pushDown(int x){
 55     if(t[x].rev){
 56         if(lc) paint(lc);
 57         if(rc) paint(rc);
 58         t[x].rev=0;
 59     }
 60     if(t[x].tag){
 61         if(lc) paint(lc,t[x].v);
 62         if(rc) paint(rc,t[x].v);
 63         t[x].tag=0;
 64     }
 65 }
 66 inline void rotate(int x){
 67     int f=t[x].fa,g=t[f].fa,c=wh(x);
 68     if(g) t[g].ch[wh(f)]=x;t[x].fa=g;
 69     t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
 70     t[x].ch[c^1]=f;t[f].fa=x;
 71     update(f);update(x);
 72 }
 73 inline void splay(int x,int tar){
 74     for(;t[x].fa!=tar;rotate(x))
 75         if(t[pa].fa!=tar) rotate(wh(pa)==wh(x)?pa:x);
 76     if(tar==0) root=x;
 77 }
 78 void build(int l,int r,int x){
 79     int mid=(l+r)>>1;
 80     t[x].v=a[mid];
 81     if(l==r){t[x].sum=t[x].lm=t[x].rm=t[x].mx=t[x].v;t[x].size=1;return;}
 82     if(l<mid){lc=nw();t[lc].fa=x;build(l,mid-1,lc);}
 83     if(mid<r){rc=nw();t[rc].fa=x;build(mid+1,r,rc);}
 84     update(x);//printf("build %d %d %d  %d %d %d\n",l,r,t[x].sum,t[x].mx,t[lc].mx,t[rc].mx);
 85 }
 86 //int build(int l,int r){
 87 //    if(l>r) return 0;
 88 //    int mid=(l+r)>>1,x=nw();
 89 //    lc=build(l,mid-1);rc=build(mid+1,r);
 90 //    t[lc].fa=t[rc].fa=x;
 91 //    t[x].v=a[mid];
 92 //    t[x].sum=t[x].lm=t[x].rm=t[x].mx=t[x].v;t[x].size=1;
 93 //    update(x);
 94 //    return x;
 95 //}
 96 int kth(int k){
 97     int x=root,ls=0;
 98     while(x){
 99         pushDown(x);
100         int _=ls+t[lc].size;
101         if(_<k&&k<=_+1) return x;
102         if(k<=_) x=lc;
103         else ls=_+1,x=rc;
104     }
105     return -1;
106 }
107 void Insert(int k,int tot){
108     for(int i=1;i<=tot;i++) a[i]=read();
109     int p=kth(k+1);splay(p,0);
110     int x=kth(k+2);splay(x,p);
111     lc=nw();t[lc].fa=x;
112     build(1,tot,lc);
113     update(x);update(p);
114 }
115 void erase(int x){
116     if(!x) return;
117     st[++top]=x;
118     if(lc) erase(lc);
119     if(rc) erase(rc);
120 }
121 void Delete(int k,int tot){
122     int p=kth(k);splay(p,0);
123     int x=kth(k+tot+1);splay(x,p);
124     erase(lc);
125     t[lc].fa=0;lc=0;
126     update(x);update(p);
127 }
128 void Make(int k,int tot,int v){
129     int p=kth(k);splay(p,0);
130     int x=kth(k+tot+1);splay(x,p);
131     paint(lc,v);
132     update(x);update(p);
133 }
134 void Reverse(int k,int tot){
135     int p=kth(k);splay(p,0);
136     int x=kth(k+tot+1);splay(x,p);
137     paint(lc);
138     update(x);update(p);
139 }
140 int Sum(int k,int tot){
141     int p=kth(k);splay(p,0);
142     int x=kth(k+tot+1);splay(x,p);
143     return t[lc].sum;
144 }
145 int main(){
146     n=read();m=read();
147     for(int i=1;i<=n;i++) a[i+1]=read();a[1]=a[n+2]=-INF;
148     t[0].mx=t[0].lm=t[0].rm=-INF;t[0].sum=0;
149     root=nw();
150     build(1,n+2,root);
151     for(int i=1;i<=m;i++){
152         scanf("%s",s);
153         if(s[0]==‘I‘) pos=read(),tot=read(),Insert(pos,tot);
154         else if(s[0]==‘D‘) pos=read(),tot=read(),Delete(pos,tot);
155         else if(s[4]==‘-‘) pos=read(),tot=read(),v=read(),Make(pos,tot,v);
156         else if(s[0]==‘R‘) pos=read(),tot=read(),Reverse(pos,tot);
157         else if(s[0]==‘G‘) pos=read(),tot=read(),printf("%d\n",Sum(pos,tot));
158         else if(s[3]==‘-‘) printf("%d\n",t[root].mx);
159     }
160 }


时间: 2024-12-14 18:06:44

BZOJ1500: [NOI2005]维修数列[splay ***]的相关文章

[bzoj1500][NOI2005 维修数列] (splay区间操作)

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操作,向输出文件依次

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

【bzoj1500】维修数列——splay

splay的高级题目,有splay的全部操作,然而本蒟蒻竟不自量力地把这道题作为splay的入门题,然后就学(mi)习(man)了一个星期-- 第一次是对着cyc的模版码的,万分感谢>< 第二次就自己码了一个小时(弱......) 就作为一个splay学习的模版吧! #include<cstdio> #include<cstring> #include<iostream> #include<queue> const int maxn=5e5+10

BZOJ1500 NOI2005 维修数列 平衡树

题意:给定一个数列,要求维护:1.在p之后加入tot个数  2.删除p之后tot个数  3.将p之后tot个数修改为c  4.翻转p之后tot个数  5.输出p之后tot个数的和  6.输出整个数列的最大子段和. 题解:平衡树很经典的题目了……主要说一下4和6操作,4的话因为翻转操作是可以分治的,所以可以用翻转标记:6我们维护一个节点所维护的区间的的最大子段和ms.从左开始的最大子段和lms.从右开始的最大子段和rms,显然有ms=max(lchild->ms,rchild->ms,lchil

HYSBZ 1500 [NOI2005]维修数列 splay

解题思路:终于把这道splay神题A掉了,splay专题也算是告一段落了,这个题主要的坑点,还是旋转和区间合并结合. 解题代码: 1 // File Name: hysbz1500.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月10日 星期五 10时41分03秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set>

bzoj1500: [NOI2005]维修数列

splay. 就是splay,没别的了. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 600000 + 10; const int inf = 0x3f3f3f3f; struct Splay { int v[maxn],s[maxn],sum[maxn]; int l[maxn],r[maxn],f[maxn]; int max

[BZOJ1500]NOI2005 维护数列|splay

这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛..一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了..然后想了很久突然顿悟..貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛..(当时太弱) 然后我就一口气写了下来.. 对每个节点维护size,sum,maxsum,maxpre,maxpos(这两个用于更新maxsum),same,rev(这两个是lazy标

bzoj1500 维修数列 splay

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 10482  Solved: 3234[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印