[ZJOI2007]报表统计
链接:https://www.luogu.org/problemnew/show/P1110
题解:
一道不错的模板题
对于第一个询问,只需维护一个支持删除的堆
方法1.再维护一个堆,将删除的数加入这个堆,每次取元素时判断一下是否和另一个堆相等
方法2.利用左偏树可以删除任意节点(太久不写都忘了)
当然也可以维护一颗平衡树
对于第二个询问,只需弄一颗平衡树求它的前驱后继就可以了
代码:
#include <bits/stdc++.h> using namespace std; #define INF 2000000000 const int maxn=510000; int ans,num,a[maxn*2],n,m,pre[maxn*2],root,v[maxn*2],dis[maxn*2], left1[maxn*2],right1[maxn*2],fa[maxn*2],now,last[maxn*2],root2, fa1[maxn*2],leftson[maxn*2],rightson[maxn*2],count2[maxn*2],data[maxn*2]; char c[10]; int merge(int r1,int r2) { if (r1==0||r2==0) return(r1+r2); if (v[r1]>v[r2]) swap(r1,r2); right1[r1]=merge(right1[r1],r2); fa1[right1[r1]]=r1; if (dis[left1[r1]]<dis[right1[r1]]) swap(left1[r1],right1[r1]); dis[r1]=dis[right1[r1]]+1; return(r1); } void delete1(int x) { if (x==0) return; int p=merge(left1[x],right1[x]),q=fa1[x]; fa1[p]=q; if (x==root2) root2=p; if (q) { if (left1[q]==x) left1[q]=p; else right1[q]=p; } while (q) { if (dis[left1[q]]<dis[right1[q]]) swap(left1[q],right1[q]); if (dis[right1[q]]+1==dis[q]) return ; dis[q]=dis[right1[q]]+1; q=fa1[q]; } } void updata(int x) { count2[x]=count2[leftson[x]]+count2[rightson[x]]; } void rotate(int x,int y) { int father=fa[x]; // down(father); down(x); if (y==1) { rightson[father]=leftson[x]; if (leftson[x]) fa[leftson[x]]=father; } else { leftson[father]=rightson[x]; if (rightson[x]) fa[rightson[x]]=father; } fa[x]=fa[father]; if (fa[father]) { if (leftson[fa[father]]==father) leftson[fa[father]]=x; else rightson[fa[father]]=x; } fa[father]=x; if (y==1) leftson[x]=father; else rightson[x]=father; updata(father); updata(x); } void splay(int x,int goal) { if (x==root) return; int father; while (fa[x]!=goal) { father=fa[x]; if (fa[father]==goal) { if (x==leftson[father]) rotate(x,2); else rotate(x,1); } else { if (father==leftson[fa[father]]) { if (x==leftson[father]) rotate(father,2),rotate(x,2); else rotate(x,1),rotate(x,2); } else { if (x==rightson[father]) rotate(father,1),rotate(x,1); else rotate(x,2),rotate(x,1); } } } if (goal==0) root=x; } void insert2(int x) { int y=root; while (y) { count2[y]++; if (x<data[y]) { if (!leftson[y]) break; y=leftson[y]; } else { if (!rightson[y]) break; y=rightson[y]; } } data[++num]=x; fa[num]=y; count2[num]=1; if (x>data[y]) rightson[y]=num; else leftson[y]=num; splay(num,0); } void getans(int x) { int y=root,maxn=-INF; while (y) { if (data[y]<=x) maxn=max(maxn,data[y]); if (data[y]<=x) y=rightson[y]; else y=leftson[y]; } ans=min(ans,abs(maxn-x)); y=root;int minn=INF; while (y) { if (data[y]>=x) minn=min(minn,data[y]); if (data[y]>=x) y=leftson[y]; else y=rightson[y]; } ans=min(ans,abs(minn-x)); } int main() { freopen("noip.in","r",stdin); freopen("noip.out","w",stdout); cin>>n>>m; ans=INF; for (int i=1;i<=n;i++) cin>>a[i]; for (int i=1;i<=n;i++) getans(a[i]), insert2(a[i]); for (int i=1;i<n;i++) { v[++now]=abs(a[i+1]-a[i]); root2=merge(root2,now); last[i]=now; pre[i]=a[i]; } pre[n]=a[n]; for (int i=1;i<=m;i++) { int d,e,f; cin>>c; if (c[4]=='R') { cin>>d>>e; delete1(last[d]); v[++now]=abs(pre[d]-e); root2=merge(root2,now); v[++now]=abs(a[d+1]-e); root2=merge(root2,now); last[d]=now; pre[d]=e; getans(e); insert2(e); } if (c[4]=='S') { cout<<ans<<endl; } if (c[4]=='G') { cout<<v[root2]<<endl; } } }