bzoj1500: [NOI2005]维修数列(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=1500
1、覆盖标记用INF表示无覆盖标记,要求可能用0覆盖
2、代表空节点的0号节点和首尾的两个虚拟节点,所有有关取max的信息全部设为负无穷,但注意不要无穷相加爆掉int
3、空间,用一个队列回收已删除的节点的编号
4、建树的时候采用的笛卡尔树的构造方式,但并没有比错误的忽略优先级的build快多少
5、手写的max快
inline
int
& max(
int
&x,
int
&y) {
return
x > y ? x : y; }
#define max(x, y) ((x) > (y) ? (x) : (y))
#include<queue> #include<cstdio> #include<cstdlib> #include<iostream> //#include<algorithm> using namespace std; #define N 500005 #define INF 1e9 int tot,root; int pri[N],val[N]; int sum[N],mxr[N],mxl[N],mx[N]; int ch[N][2],siz[N]; bool rev[N]; int tag[N]; int pos,cnt,w; int a[N]; queue<int>trash; int st[N],top; void read(int &x) { x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar();} while(isdigit(c)) { x=x*10+c-'0'; c=getchar();} x*=f; } inline int& max(int &x, int &y) { return x > y ? x : y; } void update(int x) { int l=ch[x][0],r=ch[x][1]; siz[x]=siz[l]+siz[r]+1; sum[x]=sum[l]+sum[r]+val[x]; mx[x]=max(mx[l],mx[r]); mx[x]=max(mx[x],mxr[l]+val[x]); mx[x]=max(mx[x],mxl[r]+val[x]); mx[x]=max(mx[x],mxr[l]+mxl[r]+val[x]); mx[x]=max(mx[x],val[x]); mxr[x]=max(mxr[r],sum[r]+mxr[l]+val[x]); mxr[x]=max(mxr[x],sum[r]+val[x]); mxl[x]=max(mxl[l],sum[l]+mxl[r]+val[x]); mxl[x]=max(mxl[x],sum[l]+val[x]); } void down(int x) { if(rev[x]) { int l=ch[x][0],r=ch[x][1]; if(l) { swap(ch[l][0],ch[l][1]); swap(mxl[l],mxr[l]); rev[l]^=1; } if(r) { swap(ch[r][0],ch[r][1]); swap(mxl[r],mxr[r]); rev[r]^=1; } rev[x]^=1; } if(tag[x]!=INF) { int l=ch[x][0],r=ch[x][1]; if(l) { val[l]=tag[x]; sum[l]=mxl[l]=mxr[l]=mx[l]=siz[l]*tag[x]; tag[l]=tag[x]; } if(r) { val[r]=tag[x]; sum[r]=mxl[r]=mxr[r]=mx[r]=siz[r]*tag[x]; tag[r]=tag[x]; } tag[x]=INF; } } int newnode(int v) { int now; if(!trash.empty()) now=trash.front(),trash.pop(); else now=++tot; siz[now]=1; val[now]=v; pri[now]=rand(); tag[now]=INF; sum[now]=mx[now]=mxl[now]=mxr[now]=v; rev[now]=false; ch[now][0]=ch[now][1]=0; return now; } int build(int l,int r) { int now,last; top=0; for(int i=l;i<=r;++i) { now=newnode(a[i]); last=0; while(top && pri[st[top]]>pri[now]) { update(st[top]); last=st[top--]; } if(top) ch[st[top]][1]=now; ch[now][0]=last; st[++top]=now; } while(top) update(st[top--]); return st[1]; } void split(int now,int p,int &x,int &y) { if(!now) x=y=0; else { down(now); if(p<=siz[ch[now][0]]) { y=now; split(ch[now][0],p,x,ch[now][0]); } else { x=now; split(ch[now][1],p-siz[ch[now][0]]-1,ch[now][1],y); } update(now); } } int merge(int x,int y) { if(x) down(x); if(y) down(y); if(!x || !y) return x+y; if(pri[x]<pri[y]) { ch[x][1]=merge(ch[x][1],y); update(x); return x; } else { ch[y][0]=merge(x,ch[y][0]); update(y); return y; } } int find(int k) { int now=root; while(1) { down(now); if(k<=siz[ch[now][0]]) now=ch[now][0]; else { k-=siz[ch[now][0]]; if(k==1) return now; k--; now=ch[now][1]; } } } void insert() { read(pos); read(cnt); pos++; for(int i=1;i<=cnt;++i) read(a[i]); int rt=build(1,cnt); int a,b; split(root,pos,a,b); int e=merge(a,rt); root=merge(e,b); } void del(int x) { if(!x) return; trash.push(x); del(ch[x][0]); del(ch[x][1]); } void solve(int ty) { read(pos); read(cnt); pos++; int a,b; split(root,pos+cnt-1,a,b); int c,d; split(a,pos-1,c,d); if(ty==1) { del(d); root=merge(c,b); return; } if(ty==2) { read(w); tag[d]=w; val[d]=w; sum[d]=mxl[d]=mxr[d]=mx[d]=siz[d]*w; } else if(ty==3) { rev[d]^=1; swap(ch[d][0],ch[d][1]); swap(mxl[d],mxr[d]); } else if(ty==4) printf("%d\n",sum[d]); root=merge(merge(c,d),b); } int main() { mx[0]=mxl[0]=mxr[0]=-7e8; int n,m; read(n); read(m); for(int i=2;i<=n+1;++i) read(a[i]); a[1]=a[n+2]=-7e8; root=build(1,n+2); char s[12]; while(m--) { scanf("%s",s); if(s[0]=='I') insert(); else if(s[0]=='D') solve(1); else if(s[2]=='K') solve(2); else if(s[0]=='R') solve(3); else if(s[0]=='G') solve(4); else printf("%d\n",mx[root]); } }
1500: [NOI2005]维修数列
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 15972 Solved: 5312
[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
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
10
1
10
HINT