bzoj5159 [Tjoi2014]电影评分(splay+后缀平衡树)

按道理应该是一定会挂精度的,正解应该是后缀平衡树来比较两个数的小数部分的大小。但是数据水,直接long double是可以水过的【逃】。正解待更新。。

tips:注意是最早的而不是标号最小的,我们还要枚举一下题意,发现他说的是如果评分相同就按出现时间给排名【逃】。

3.13upd:更新正解
我们现在的问题是如何比较两个实数的大小。我们可以直接比较整数部分,
注意到小数部分可以看成一个二进制下的01串,两种操作:

1、每次加入一个新电影,就相当于把某个字符串复制过来
2、每次修改评分就相当于在这个01串前加入一个字符0或1

于是问题就转化为一个字符串问题:支持复制字符串,在某个字符串前面加入一个字符,比较两个字符串的字典序大小。

可以用后缀平衡树来做,正如他名字所说的那样,这个数据结构就是用平衡树维护了一下后缀排名。如果使用重量平衡树打标记就可以实现 O(1) O ( 1 ) 查询两个后缀的字典序大小,用treap来每次旋转时暴力重构,期望复杂度是 O(logn) O ( l o g n ) 的。
所以总的复杂度就是 O(nlogn) O ( n l o g n )

关于后缀平衡树及重量平衡树的学习可以参考clj的2014国家集训队论文。

splay+后缀平衡树

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define inf 1LL<<60
#define ll long long
#define N 100010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
char op[5];
inline void get_S(){
    char ch=gc();
    while(ch<'A'||ch>'Z') ch=gc();op[1]=ch;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,fa[N],c[N][2],sz[N],last[N],rt=0,tim[N],owo=0,v[N],dec[N];
int ls[N],rs[N],fir[N],sec[N],rnd[N],num=0,_rt=0;ll tag[N];
inline int comp(int x,int y){//1-> x<y 0-> x>y 2-> x==y
    if(fir[x]<fir[y]) return 1;if(fir[x]>fir[y]) return 0;
    if(tag[sec[x]]<tag[sec[y]]) return 1;
    if(tag[sec[x]]>tag[sec[y]]) return 0;return 2;
}
inline void rebuild(int p,ll l,ll r){
    if(!p) return;
    ll mid=l+r>>1;tag[p]=mid;rebuild(ls[p],l,mid);rebuild(rs[p],mid+1,r);
}
inline void rturn(int &y,ll l,ll r){
    int x=ls[y];ls[y]=rs[x];rs[x]=y;y=x;rebuild(y,l,r);
}
inline void lturn(int &y,ll l,ll r){
    int x=rs[y];rs[y]=ls[x];ls[x]=y;y=x;rebuild(y,l,r);
}
int ff;
inline void _ins(int &p,ll l,ll r){
    if(!p){p=num;ls[p]=rs[p]=0;rnd[p]=rand();tag[p]=l+r>>1;return;}
    int op=comp(num,p);ll mid=l+r>>1;
    if(op==2){ff=p;return;}
    if(op==1){_ins(ls[p],l,mid);if(rnd[ls[p]]<rnd[p]) rturn(p,l,r);return;}
    _ins(rs[p],mid+1,r);if(rnd[rs[p]]<rnd[p]) lturn(p,l,r);
}
inline void update(int p){
    int l=c[p][0],r=c[p][1];
    sz[p]=sz[l]+sz[r]+1;
}
inline void rotate(int x,int &k){
    int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
    if(y==k) k=x;
    else c[z][y==c[z][1]]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &k){
    while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k){
            if(x==c[y][1]^y==c[z][1]) rotate(x,k);
            else rotate(y,k);
        }rotate(x,k);
    }
}
inline bool cless(int x,int y){
    if(v[x]>v[y]) return 1;if(v[x]<v[y]) return 0;
    if(tag[dec[x]]>tag[dec[y]]) return 1;
    if(tag[dec[x]]<tag[dec[y]]) return 0;
    return tim[x]<tim[y];
}
inline void ins(int &p,int x,int Fa){
    if(!p){p=x;fa[p]=Fa;c[p][0]=c[p][1]=0;splay(p,rt);return;}
    if(cless(x,p)) ins(c[p][0],x,p);
    else ins(c[p][1],x,p);
}
inline void del(int x){
    splay(x,rt);
    if(c[x][0]*c[x][1]==0){
        rt=c[x][0]+c[x][1];fa[c[x][0]+c[x][1]]=0;return;
    }int pre=c[x][0],succ=c[x][1];
    while(c[pre][1]) pre=c[pre][1];
    while(c[succ][0]) succ=c[succ][0];
    splay(pre,rt);splay(succ,c[pre][1]);
    c[succ][0]=fa[x]=0;update(succ);update(pre);
}
inline int getkth(int p,int k){
    if(sz[c[p][0]]+1==k) return p;
    if(k<=sz[c[p][0]]) return getkth(c[p][0],k);
    return getkth(c[p][1],k-sz[c[p][0]]-1);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();srand(20000712);
    while(n--){
        get_S();if(op[1]=='Q'){printf("%d\n",getkth(rt,read()));continue;}
        if(op[1]=='R'){
            int x=read(),tot=read(),res=0;
            while(tot--){int y=read();if(tim[last[y]]>tim[res]) res=last[y];last[y]=x;}
            v[x]=v[res];dec[x]=dec[res];tim[x]=++owo;sz[x]=1;ins(rt,x,0);continue;
        }if(op[1]=='C'){
            int x=read(),val=read();del(x);v[x]+=val;
            if(v[x]&1||dec[x]){
                ++num;sec[num]=dec[x];fir[num]=v[x]&1;dec[x]=num;
                ff=0;_ins(_rt,0,inf);if(ff) num--,dec[x]=ff;
            }v[x]>>=1;ins(rt,x,0);
        }
    }return 0;
}

splay+long double

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ld long double
#define inf 0x3f3f3f3f
#define N 100010
#define eps 1e-60
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
char op[5];
inline void get_S(){
    char ch=gc();
    while(ch<'A'||ch>'Z') ch=gc();op[1]=ch;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
inline ld abs(ld x){return x<0?-x:x;}
int n,fa[N],c[N][2],sz[N],last[N],rt=0,tim[N],owo=0;ld v[N];
inline void update(int p){
    int l=c[p][0],r=c[p][1];
    sz[p]=sz[l]+sz[r]+1;
}
inline void rotate(int x,int &k){
    int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
    if(y==k) k=x;
    else c[z][y==c[z][1]]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &k){
    while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k){
            if(x==c[y][1]^y==c[z][1]) rotate(x,k);
            else rotate(y,k);
        }rotate(x,k);
    }
}
inline void ins(int &p,int x,int Fa){
    if(!p){p=x;fa[p]=Fa;c[p][0]=c[p][1]=0;splay(p,rt);return;}
    if(v[x]>v[p]||abs(v[x]-v[p])<=eps&&tim[x]<tim[p]) ins(c[p][0],x,p);
    else ins(c[p][1],x,p);
}
inline void del(int x){
    splay(x,rt);
    if(c[x][0]*c[x][1]==0){
        rt=c[x][0]+c[x][1];fa[c[x][0]+c[x][1]]=0;return;
    }int pre=c[x][0],succ=c[x][1];
    while(c[pre][1]) pre=c[pre][1];
    while(c[succ][0]) succ=c[succ][0];
    splay(pre,rt);splay(succ,c[pre][1]);
    c[succ][0]=fa[x]=0;update(succ);update(pre);
}
inline int getkth(int p,int k){
    if(sz[c[p][0]]+1==k) return p;
    if(k<=sz[c[p][0]]) return getkth(c[p][0],k);
    return getkth(c[p][1],k-sz[c[p][0]]-1);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();
    while(n--){
        get_S();if(op[1]=='Q'){printf("%d\n",getkth(rt,read()));continue;}
        if(op[1]=='R'){
            int x=read(),tot=read(),res=0;
            while(tot--){int y=read();if(tim[last[y]]>tim[res]) res=last[y];last[y]=x;}
            v[x]=v[res];tim[x]=++owo;sz[x]=1;ins(rt,x,0);continue;
        }if(op[1]=='C'){
            int x=read(),val=read();
            del(x);v[x]=(v[x]+val)*0.5;ins(rt,x,0);
        }
    }return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值