BZOJ 1503 郁闷的出纳员
一开始潜意识就认为是splay模板,打了140+行,还调了很久(自己码力太弱了)
然后听学长说不用打标记,可以存全局的增减值,于是写了一个60-的权值线段树,非常快且好看地就A掉了
//Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<vector> #define lc ch[x][0] #define rc ch[x][1] const int maxn=100005; using namespace std; int ans,tot,root,n,mi,x,y,v[maxn],cnt[maxn],ch[maxn][2],p[maxn],sz[maxn],lz[maxn]; char s[5]; void update(int x) {sz[x]=sz[lc]+sz[rc]+cnt[x];} void rotate(int x){ int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1; if(z) {ch[z][y==ch[z][1]]=x;} p[x]=z; ch[y][l]=ch[x][r]; p[ch[y][l]]=y; ch[x][r]=y; p[y]=x; update(y); update(x); } void down(int x){ if(!lz[x]) return; if(lc) {v[lc]+=lz[x]; lz[lc]+=lz[x];} if(rc) {v[rc]+=lz[x]; lz[rc]+=lz[x];} lz[x]=0; } void splay(int x){ if(x==root) return; static int s[maxn],top; for(int i=x;i;i=p[i]) s[++top]=i; while(top) down(s[top--]); for(;p[x];rotate(x)){ int y=p[x],z=p[y]; if(z){ ((y==ch[z][1])^(z==ch[y][1]))?rotate(x):rotate(y); } } root=x; } int pre(){ x=root; x=lc; while(rc) x=rc; return x; } int rak(int k){ for(x=root;x;){ if(v[x]==k) { splay(x); return x; } down(x); if(v[x]<k) x=rc; else x=lc; } } int kth(int k){ for(x=root;x;){ if(k>=sz[lc]+1&&k<=sz[lc]+cnt[x]) return x; down(x); if(k<=sz[lc]) x=lc; else k-=(sz[lc]+cnt[x]),x=rc; } } int kth2(int k){ for(x=root;x;){ if(k>=sz[rc]+1&&k<=sz[rc]+cnt[x]) return x; down(x); if(k<=sz[rc]) x=rc; else k-=(sz[rc]+cnt[x]),x=lc; } } void del(int y){ x=rak(y); x=root; if(cnt[x]>1) {cnt[x]--;update(x);return;} if(!lc) root=rc,p[root]=0; else if(!rc) root=lc,p[root]=0; else { int z=pre(); splay(z); x=root; if(ch[rc][1]) p[ch[rc][1]]=x; rc=ch[rc][1]; update(x); } } void insert(int y){ x=root; int l=0,fa=0; if(!x) { root=++tot; v[root]=y; sz[tot]=cnt[tot]=1; return; } for(;;){ if(!x){ x=++tot; p[x]=fa; v[x]=y; ch[fa][l]=x; sz[x]=cnt[x]=1; splay(x); return; } down(x); if(v[x]==y){ cnt[x]++; splay(x); return; } if(v[x]>y) fa=x,l=0,x=lc; else fa=x,l=1,x=rc; } } int main() { scanf("%d%d",&n,&mi); while(n--){ scanf("%s%d",s,&y); if(s[0]=='I') {if(y>=mi) insert(y);} else if(s[0]=='A') {v[root]+=y;lz[root]+=y;} else if(s[0]=='S'){ insert(mi+y); x=root; ans+=sz[lc]; p[lc]=0; lc=0; update(x); del(mi+y); v[root]-=y; lz[root]-=y; } else if(s[0]=='F') { if(y>sz[root]) cout<<"-1"<<endl; else printf("%d\n",v[kth2(y)]);} } printf("%d\n",ans); return 0; }
很神奇的是这个splay版的如果不写Kth2而是直接用kth找就会WA?一直没找出是什么问题。。
//Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<vector> #define mid ((l+r)>>1) const int maxn=100005; const int nn=1e9; using namespace std; int n,y,mi,root,tot,ans,sg[maxn<<3],ls[maxn<<3],rs[maxn<<3],lzz; char s[5]; void add(int &x,int l,int r,int v){ if(!x) x=++tot; if(l==r) {sg[x]++;return;} if(v<=mid) add(ls[x],l,mid,v); else add(rs[x],mid+1,r,v); sg[x]=sg[ls[x]]+sg[rs[x]]; } int query(int x,int l,int r,int k){ if(l==r) return l+lzz; if(sg[ls[x]]>=k) return query(ls[x],l,mid,k); else return query(rs[x],mid+1,r,k-sg[ls[x]]); } void check(int x,int l,int r,int v){ if(ls[x]){ if(mid<v) {ans+=sg[ls[x]]; ls[x]=0;} else check(ls[x],l,mid,v); } if(rs[x]) if(mid+1<v) check(rs[x],mid+1,r,v); sg[x]=sg[ls[x]]+sg[rs[x]]; } int main() { scanf("%d%d",&n,&mi); while(n--){ scanf("%s%d",s,&y); if(s[0]=='I') { if(y<mi) /*ans++*/; else{ add(root,-nn,nn,y-lzz); } } else if(s[0]=='A') lzz+=y; else if(s[0]=='S'){ lzz-=y; check(root,-nn,nn,mi-lzz); } else if(s[0]=='F') { if(y>sg[root]) cout<<"-1"<<endl; else printf("%d\n",query(1,-nn,nn,sg[root]-y+1)); } } printf("%d\n",ans); return 0; }