【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[maxn][2],f[maxn],A[maxn],L[maxn],R[maxn],M[maxn],sum[maxn],en[maxn],g[maxn],s[maxn]; //关系类:f父亲 t儿子 | 数值类:num值 L左起最大子段和 R右起最大子段和 M最大子段和 sum和 s结点数 | 标记类:en覆盖标记 g翻转标记 queue<int>q; int read() { char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t; } int Node(int fa,int num) { int sz=q.front();q.pop(); t[sz][0]=t[sz][1]=en[sz]=g[sz]=0; s[sz]=1;f[sz]=fa;A[sz]=L[sz]=R[sz]=M[sz]=sum[sz]=num; return sz; } void count(int x)//与线段树更新不同,记得加自身 { L[x]=max(L[t[x][0]],sum[t[x][0]]+A[x]+max(0,L[t[x][1]])); R[x]=max(R[t[x][1]],sum[t[x][1]]+A[x]+max(0,R[t[x][0]])); M[x]=max(0,R[t[x][0]])+A[x]+max(0,L[t[x][1]]); M[x]=max(M[x],max(M[t[x][0]],M[t[x][1]])); sum[x]=sum[t[x][0]]+A[x]+sum[t[x][1]]; s[x]=s[t[x][0]]+1+s[t[x][1]]; } void pushdown(int x) { if(g[x]) { g[t[x][0]]^=1;g[t[x][1]]^=1; swap(L[t[x][0]],R[t[x][0]]); swap(L[t[x][1]],R[t[x][1]]); swap(t[x][0],t[x][1]); g[x]=0; } if(en[x]) { if(t[x][0]) { en[t[x][0]]=1; A[t[x][0]]=A[x]; sum[t[x][0]]=A[x]*s[t[x][0]]; L[t[x][0]]=R[t[x][0]]=M[t[x][0]]=A[x]>0?sum[t[x][0]]:A[x]; } if(t[x][1]) { en[t[x][1]]=1; A[t[x][1]]=A[x]; sum[t[x][1]]=A[x]*s[t[x][1]]; L[t[x][1]]=R[t[x][1]]=M[t[x][1]]=A[x]>0?sum[t[x][1]]:A[x]; } en[x]=0; } } void rotate(int x) { int k=x==t[f[x]][1]; int y=f[x]; t[y][k]=t[x][!k];f[t[x][!k]]=y; if(f[y])t[f[y]][y==t[f[y]][1]]=x;f[x]=f[y];f[y]=x; t[x][!k]=y; L[x]=L[y];R[x]=R[y];M[x]=M[y];sum[x]=sum[y];s[x]=s[y]; count(y); } void splay(int x,int r) { for(int fa=f[r];f[x]!=fa;)//因为y被旋走了,所以要判断f[y] { if(f[f[x]]==fa){rotate(x);break;} int X=x==t[f[x]][1],Y=f[x]==t[f[f[x]]][1];//等号别打少…… if(X^Y)rotate(x),rotate(x); else rotate(f[x]),rotate(x); } } void find(int &x,int k) { for(int i=x;i;) { pushdown(i); if(k<=s[t[i][0]]){i=t[i][0];continue;} if(k==s[t[i][0]]+1){splay(i,x);x=i;break;} k-=s[t[i][0]]+1;i=t[i][1];//else不安全。。。 } } void build(int fa,int &x,int l,int r) { if(l>r)return; int mid=(l+r)>>1; x=Node(fa,a[mid]); build(x,t[x][0],l,mid-1); build(x,t[x][1],mid+1,r); count(x);// } void insert() { int l=read(),k=read(); for(int i=1;i<=k;i++)a[i]=read(); int r;build(0,r,1,k); find(root,l+1);find(t[root][1],1); t[t[root][1]][0]=r;f[r]=t[root][1]; count(t[root][1]);count(root);//记得count } void erase(int x) { if(!x)return; q.push(x); erase(t[x][0]); erase(t[x][1]); } void del() { int l=read(),k=read(); find(root,l);find(t[root][1],k+1); erase(t[t[root][1]][0]); t[t[root][1]][0]=0; count(t[root][1]);count(root);// } void cover() { int l=read(),k=read(),num=read(); find(root,l);find(t[root][1],k+1); int y=t[t[root][1]][0]; en[y]=1;A[y]=num; sum[y]=s[y]*A[y]; L[y]=R[y]=M[y]=A[y]>0?sum[y]:A[y]; count(t[root][1]);count(root);// } void round() { int l=read(),k=read(); find(root,l);find(t[root][1],k+1); int y=t[t[root][1]][0]; g[y]^=1; swap(L[y],R[y]); count(t[root][1]);count(root);// } void getsum() { int l=read(),k=read(); find(root,l);find(t[root][1],k+1); printf("%d\n",sum[t[t[root][1]][0]]); } void getM() { int sz=s[root]; find(root,1); find(t[root][1],sz-1); printf("%d\n",M[t[t[root][1]][0]]); } char str[20]; int main() { n=read();m=read(); a[0]=a[n+1]=root=0; for(int i=1;i<=maxn;i++)q.push(i); L[0]=R[0]=M[0]=-inf;//使空结点干扰判断,过程中需保证任何时刻都不应修改到该点的值。 for(int i=1;i<=n;i++)a[i]=read(); build(0,root,0,n+1); for(int i=1;i<=m;i++) { scanf("%s",str); if(str[2]=='S')insert(); if(str[2]=='L')del(); if(str[2]=='K')cover(); if(str[2]=='V')round(); if(str[2]=='T')getsum(); if(str[2]=='X')getM(); } return 0; }
update:现在已改用fhq-treap代替splay。