1. 程式人生 > >BZOJ 1503 郁悶的出納員

BZOJ 1503 郁悶的出納員

img amp logs efi pan ring cout sin con

一開始潛意識就認為是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

很神奇的是這個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;
}
權值線段樹

BZOJ 1503 郁悶的出納員