【BZOJ1500】[NOI2005]维修数列

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

HINT

spaly裸题,但依旧不敢保证自己能写出来,并且有很多不会的地方

  1 #include<queue>
  2 #include<cmath>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define inf 1000000000
  9 #define N 1000005
 10 using namespace std;
 11 queue<int> q;
 12 int n,m,rt,sz;
 13 int a[N],id[N],fa[N],c[N][2];
 14 int sum[N],size[N],v[N],mx[N],lx[N],rx[N];
 15 bool tag[N],rev[N];
 16 void updata(int x){
 17     int l=c[x][0],r=c[x][1];
 18     sum[x]=sum[l]+sum[r]+v[x];
 19     size[x]=size[l]+size[r]+1;
 20     mx[x]=max(mx[l],mx[r]);
 21     mx[x]=max(mx[x],rx[l]+v[x]+lx[r]);
 22     lx[x]=max(lx[l],sum[l]+v[x]+lx[r]);//?
 23     rx[x]=max(rx[r],sum[r]+v[x]+rx[l]);
 24 }
 25
 26 void pushdown(int x){
 27     int l=c[x][0],r=c[x][1];
 28     if (tag[x]){
 29         rev[x]=tag[x]=0;
 30         if (l)tag[l]=1,v[l]=v[x],sum[l]=v[x]*size[l];
 31         if (r)tag[r]=1,v[r]=v[x],sum[r]=v[x]*size[r];
 32         if (v[x]>=0){
 33             if (l)lx[l]=rx[l]=mx[l]=sum[l];
 34             if (r)lx[r]=rx[r]=mx[r]=sum[r];
 35         }
 36         else {
 37             if (l)lx[l]=rx[l]=0,mx[l]=v[l];
 38             if (r)lx[r]=rx[r]=0,mx[r]=v[r];
 39         }
 40     }
 41     if (rev[x]){
 42         rev[x]^=1;rev[l]^=1;rev[r]^=1;
 43         swap(lx[l],rx[l]);swap(lx[r],rx[r]);
 44         swap(c[l][0],c[l][1]);swap(c[r][0],c[r][1]);//?
 45     }
 46 }
 47 void rotate(int x,int &k){
 48     int l,r,y=fa[x],z=fa[y];
 49     if (c[y][0]==x) l=0;else l=1;r=l^1;
 50     if (y==k)k=x;
 51     else {if (c[z][0]==y) c[z][0]=x;else c[z][1]=x;}
 52     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
 53     c[y][l]=c[x][r];c[x][r]=y;
 54     updata(y);updata(x);
 55 }
 56
 57 void splay(int x,int &k){
 58     while (x!=k){
 59         int y=fa[x],z=fa[y];
 60         if (y!=k){
 61             if ((c[z][0]==y)^(c[y][0]==x)) rotate(x,k);
 62             else rotate(y,k);
 63         }
 64         rotate(x,k);
 65     }
 66 }
 67
 68 int find(int k,int rk){
 69     pushdown(k);
 70     int l=c[k][0],r=c[k][1];
 71     if (size[l]+1==rk) return k;
 72     if (size[l]>=rk) return find(l,rk);
 73     return find(r,rk-size[l]-1);
 74 }
 75
 76 int split(int k,int tot){
 77     int x=find(rt,k),y=find(rt,k+tot+1);
 78     splay(x,rt);splay(y,c[x][1]);
 79     return c[y][0];
 80 }
 81
 82 void build(int l,int r,int f){
 83     if (l>r) return;
 84     int mid=(l+r)>>1,last=id[f],now=id[mid];
 85     if (l==r){
 86         sum[now]=a[l];size[now]=1;
 87         tag[now]=rev[now]=0;
 88         if (a[l]>=0) lx[now]=rx[now]=mx[now]=a[l];
 89         else lx[now]=rx[now]=0,mx[now]=a[l];
 90     }
 91     else build(l,mid-1,mid),build(mid+1,r,mid);
 92     v[now]=a[mid];fa[now]=last;updata(now);
 93     c[last][mid>=f]=now;
 94 }
 95 void insert(int k,int tot){
 96     for (int i=1;i<=tot;i++){
 97         if(!q.empty())id[i]=q.front(),q.pop();
 98         else id[i]=++sz;
 99         scanf("%d",&a[i]);
100     }
101     build(1,tot,0);int z=id[(1+tot)>>1];
102     int x=find(rt,k+1),y=find(rt,k+2);
103     splay(x,rt);splay(y,c[x][1]);
104     c[y][0]=z;fa[z]=y;
105     updata(y);updata(x);
106 }
107
108 void rec(int x){
109     if (!x) return;
110     int l=c[x][0],r=c[x][1];
111     rec(l);rec(r);q.push(x);
112     fa[x]=c[x][0]=c[x][1]=tag[x]=rev[x]=0;
113 }
114
115 void erase(int k,int tot){
116     int x=split(k,tot),y=fa[x];
117     rec(x);c[y][0]=0;
118     updata(y);updata(fa[y]);
119 }
120
121 void modify(int k,int tot,int val){
122     int x=split(k,tot),y=fa[x];
123     v[x]=val;tag[x]=1;sum[x]=size[x]*val;
124     if (val>=0)lx[x]=rx[x]=mx[x]=sum[x];
125     else lx[x]=rx[x]=0,mx[x]=val;
126     updata(y);updata(fa[y]);
127 }
128
129 void rever(int k,int tot){
130     int x=split(k,tot),y=fa[x];
131     if (!tag[x]){//或许会节省一点时间
132         rev[x]^=1;
133         swap(c[x][0],c[x][1]);
134         swap(lx[x],rx[x]);
135         updata(y);updata(fa[y]);
136     }
137 }
138
139 void query(int k,int tot){
140     int x=split(k,tot);
141     printf("%d\n",sum[x]);
142 }
143
144 int main(){
145     scanf("%d%d",&n,&m);
146     mx[0]=a[1]=a[n+2]=-inf;
147     for(int i=1;i<=n;i++)scanf("%d",&a[i+1]);
148     for(int i=1;i<=n+2;i++)id[i]=i;
149     build(1,n+2,0);
150     rt=(n+3)>>1;sz=n+2;
151     int k,tot,val;
152     char ch[10];
153     while(m--)
154     {   //printf("%d\n",mx[rt]);
155         scanf("%s",ch);
156         if(ch[0]!=‘M‘||ch[2]!=‘X‘)scanf("%d%d",&k,&tot);
157         if(ch[0]==‘I‘)insert(k,tot);
158         if(ch[0]==‘D‘)erase(k,tot);
159         if(ch[0]==‘M‘)
160         {
161             if(ch[2]==‘X‘)printf("%d\n",mx[rt]);
162             else scanf("%d",&val),modify(k,tot,val);
163         }
164         if(ch[0]==‘R‘)rever(k,tot);
165         if(ch[0]==‘G‘)query(k,tot);
166     }
167     return 0;
168 }
时间: 2024-10-12 16:21:49

【BZOJ1500】[NOI2005]维修数列的相关文章

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

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

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

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

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

1500: [NOI2005]维修数列

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

BZOJ 1500: [NOI2005]维修数列

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

[NOI2005] 维修数列

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

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

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 ; ++

【BZOJ】1500: [NOI2005]维修数列

[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=5e5+10,inf=0x3f3f3f3f; int n,m,root,a[maxn],t