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

很神奇的是这个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;
}
权值线段树

 

转载于:https://www.cnblogs.com/Achenchen/p/7475065.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值