Description
小 \(\mathrm{Z}\) 发明了一套新的电影评分系统。这套系统有三种操作:发布新电影、电影评分、以及询问电影评分的排名。具体是这样运作的:如果是发布新电影,并且这部电影的所有主演之前均没有出现过,那么这部电影的评分为 0,否则这部电影的评分为最近一部与该电影至少有一个共同主演的电影的分;如果是对电影进行评分,那么这部电影的评分就变成之前评分与新的评分的平均数;如果是查询排名,则根据评分输出相应排名。评分最高的为第一名。如果有多部电影分数相同,那么输出最早的一部。电影的评分在 0 到 5 之间。
Solution
有种做法是暴力,利用快排可以在 \(\mathcal O(n)\) 的时间内求出区间第 \(k\) 大,做到总时间复杂度为 \(\mathcal O(n^2)\),吸下氧应该能过。
正解是后缀平衡树,将小数分成整数部分和小数部分,小数部分用二进制表示,然后来比较。
但正解我也不会,我就只打了 \(\mathrm{Splay}\),由于怕被卡精度于是用了 \(\mathrm{long\ double}\)。
剩下的就跟普通的 \(\mathrm{Splay}\) 差不多。
Code
#include<cstdio>
#include<algorithm>
#define N 100005
#define eps 1e-60
#define ldb long double
using namespace std;
int n,cnt,rt,t[N],lst[N],size[N],f[N],c[N][2];
ldb val[N];
char ch[16];
ldb Abs(ldb x) {return x<0?-x:x;}
void Update(int x)
{
int l=c[x][0],r=c[x][1];
size[x]=size[l]+size[r]+1;
}
void Rotate(int x,int &k)
{
int y=f[x],z=f[y],l=x==c[y][1],r=l^1;
r=l^1;
if (y==k) k=x;
else c[z][y==c[z][1]]=x;
f[c[x][r]]=y;f[y]=x;f[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
Update(x);Update(y);
}
void Splay(int x,int &k)
{
while (x!=k)
{
int y=f[x],z=f[y];
if (y!=k)
{
if (x==c[y][1]^y&&c[y][1]^y==c[z][1]) Rotate(x,k);
else Rotate(y,k);
}
Rotate(x,k);
}
}
void Insert(int &now,int x,int fa)
{
if (!now)
{
now=x;
f[now]=fa;
c[now][0]=c[now][1]=0;
Splay(now,rt);
return;
}
if (val[x]>val[now]||Abs(val[x]-val[now])<eps&&t[x]<t[now]) Insert(c[now][0],x,now);
else Insert(c[now][1],x,now);
}
void Delete(int x)
{
Splay(x,rt);
if (c[x][0]*c[x][1]==0)
{
rt=c[x][0]+c[x][1];
f[c[x][0]+c[x][1]]=0;
return;
}
int pre=c[x][0],suf=c[x][1];
while (c[pre][1]) pre=c[pre][1];
while (c[suf][0]) suf=c[suf][0];
Splay(pre,rt);Splay(suf,c[pre][1]);
c[suf][0]=f[x]=0;
Update(pre);Update(suf);
}
int Get(int now,int rk)
{
if (size[c[now][0]]+1==rk) return now;
if (rk<=size[c[now][0]]) return Get(c[now][0],rk);
return Get(c[now][1],rk-size[c[now][0]]-1);
}
int main()
{
freopen("movie.in","r",stdin);
freopen("movie.out","w",stdout);
scanf("%d",&n);
while (n--)
{
scanf("%s",ch);
if (ch[0]=='R')
{
int x,num,act,k=0;
scanf("%d%d",&x,&num);
for (int i=1;i<=num;++i)
{
scanf("%d",&act);
if (t[lst[act]]>t[k]) k=lst[act];
lst[act]=x;
}
val[x]=val[k];
t[x]=++cnt;
size[x]=1;
Insert(rt,x,0);
}
else if (ch[0]=='C')
{
int x;ldb v;
scanf("%d%Lf",&x,&v);
Delete(x);
val[x]=(val[x]+v)/2;
Insert(rt,x,0);
}
else if (ch[0]=='Q')
{
int x;
scanf("%d",&x);
printf("%d\n",Get(rt,x));
}
}
return 0;
}