按道理应该是一定会挂精度的,正解应该是后缀平衡树来比较两个数的小数部分的大小。但是数据水,直接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;
}