传送门
挺基础的平衡树题目。不过我调了将近一天= =感觉自己太弱逼了= =
主要是思路刚开始想复杂了= =维护了好几个没必要的东西,还有一些没有维护。
又一次写了300+的代码然后发现自己T了,还是T了1组QAQ
然后忍痛重写= =思路对了之后没多久就A了= =
不过还是感谢ShallWe的hash大法= =
维护一下每一个点在tree中的编号,然后del的时候就可以直接转了。
贴上T了一组的代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
const int max_n=3e5+5;
const int INF=2e9;
map <string,int> list,score;
map <int,string> name;
int n,tot,totplayer;
string Name,s;
int Score;
int f[max_n],ch[max_n][2],size[max_n],key[max_n],player[max_n];
int root,sz;
int printtot,printcnt;
inline bool get(int x){
return ch[ f[x] ][1]==x;
}
inline void update(int x){
if (x){
size[x]=1;
if (ch[x][0]) size[x]+=size[ ch[x][0] ];
if (ch[x][1]) size[x]+=size[ ch[x][1] ];
}
}
inline void rotate(int x){
int old=f[x],oldf=f[old],which=get(x);
ch[old][which]=ch[x][which^1];
f[ ch[old][which] ]=old;
ch[x][which^1]=old;
f[old]=x;
f[x]=oldf;
if (oldf)
ch[oldf][ ch[oldf][1]==old ]=x;
update(old);
update(x);
}
inline void splay(int x,int tar){
for (int fa;(fa=f[x])!=tar;rotate(x))
if (f[fa]!=tar)
rotate( (get(x)==get(fa)) ?fa:x);
if (!tar) root=x;
}
//返回分数为x,名字编号为y的点的排名
inline int find(int x,int y){
int now=root,ans=0;
while (1){
if (x<key[now])
now=ch[now][0];
else{
if (x==key[now]){
if (y==player[now]){
if (ch[now][0])
ans+=size[ ch[now][0] ];
return ans+1;
}
if (y<player[now])
now=ch[now][0];
else{
if (ch[now][0])
ans+=size[ ch[now][0] ];
ans+=1;
now=ch[now][1];
}
}
else{
if (ch[now][0])
ans+=size[ ch[now][0] ];
ans+=1;
now=ch[now][1];
}
}
}
}
//权值小于x,且最靠后
inline int Insert_Find_Pre(int x){
int now=root,ans;
while (1){
if (key[now]<x){
ans=now;
if (ch[now][1]) now=ch[now][1];
else break;
}
else
if (ch[now][0])
now=ch[now][0];
else
break;
}
return ans;
}
//权值大于或等于x,且最靠前
inline int Insert_Find_Next(int x){
int now=root,ans;
while (1){
if (key[now]>=x){
ans=now;
if (ch[now][0]) now=ch[now][0];
else break;
}
else
if (ch[now][1])
now=ch[now][1];
else
break;
}
return ans;
}
//权值小于x,或者权值等于x且序号小于x,且最靠后
inline int Delete_Find_Pre(int x,int Name){
int now=root,ans;
while (1){
if (key[now]<x||key[now]==x&&player[now]<Name){
ans=now;
if (ch[now][1]) now=ch[now][1];
else break;
}
else
if (ch[now][0])
now=ch[now][0];
else
break;
}
return ans;
}
//权值大于x,或者权值等于x且序号大于于x,且最靠后
inline int Delete_Find_Next(int x,int Name){
int now=root,ans;
while (1){
if (key[now]>x||key[now]==x&&player[now]>Name){
ans=now;
if (ch[now][0]) now=ch[now][0];
else break;
}
else
if (ch[now][1])
now=ch[now][1];
else
break;
}
return ans;
}
inline void insert(int x,int Name){
if (root==0){
root=++sz;
f[sz]=ch[sz][0]=ch[sz][1]=0;
size[sz]=1;
key[sz]=x;
player[sz]=Name;
return;
}
if (!ch[root][0]&&!ch[root][1]){
ch[root][ key[root]<x ]=++sz;
f[sz]=root;
ch[sz][0]=ch[sz][1]=0;
size[sz]=1;
key[sz]=x;
player[sz]=Name;
update(root);
return;
}
int aa=Insert_Find_Pre(x);
int bb=Insert_Find_Next(x);
splay(aa,0);
splay(bb,aa);
ch[ ch[root][1] ][0]=++sz;
f[sz]=ch[root][1];
ch[sz][0]=ch[sz][1]=0;
size[sz]=1;
key[sz]=x;
player[sz]=Name;
update(ch[root][1]);
update(root);
}
inline void del(int x,int Name){
int aa=Delete_Find_Pre(x,Name);
int bb=Delete_Find_Next(x,Name);
splay(aa,0);
splay(bb,aa);
ch[ ch[root][1] ][0]=0;
update(ch[root][1]);
update(root);
}
//返回排名为x的点的编号
inline int findnum(int x){
int now=root,ans;
while (1){
if (ch[now][0]&&x<=size[ ch[now][0] ])
now=ch[now][0];
else{
int temp=1;
if (ch[now][0])
temp+=size[ ch[now][0] ];
if (x<=temp) return now;
x-=temp;
now=ch[now][1];
}
}
}
inline void print(int x){
int now=x;
if (ch[now][1]) print(ch[now][1]);
printtot++;
string s=name[player[now]];
int len=s.length();
for (int i=0;i<len;++i)
putchar(s[i]);
if (printtot!=printcnt) putchar(' ');
if (ch[now][0]) print(ch[now][0]);
}
inline void Query(int L,int R){
int y=totplayer-L+1;
int x=totplayer-(L+R-1)+1;
//x-1 y+1
int aa=findnum(x);
int bb=findnum(y+2);
splay(aa,0);
splay(bb,aa);
printtot=0; printcnt=R;
print( ch[ ch[root][1] ][0] );
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("my.out","w",stdout);
scanf("%d",&n);
insert(-INF,INF+2);
insert(INF,INF+1);
tot=250000+1;
for (int i=1;i<=n;++i){
char c=getchar();
while (c!='+'&&c!='?') c=getchar();
if (c=='+'){
Name="";
char cc;
while (1){
cc=getchar();
if (cc==' ')
break;
Name=Name+cc;
}
scanf("%d",&Score);
if (list[Name]){
del( score[Name],list[Name] );
list[Name]=--tot;
name[tot]=Name;
score[Name]=Score;
insert( Score,list[Name] );
}
else{
totplayer++;
list[Name]=--tot;
name[tot]=Name;
score[Name]=Score;
insert( Score,list[Name] );
}
}
else{
Name="";
char cc;
while (1){
cc=getchar();
if (cc=='\n') break;
Name+=cc;
}
if (Name[0]>='0'&&Name[0]<='9'){
int Index=0;
int len=Name.length();
for (int j=0;j<len;++j)
Index=Index*10+Name[j]-'0';
int L=Index;
int R=min(totplayer-Index+1,10);
Query(L,R);
putchar('\n');
}
else{
int ans=find( score[Name],list[Name] )-1;
printf("%d\n",totplayer-ans+1);
}
}
}
return 0;
}
AC code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
const int max_n=3e5+5;
const int INF=2e9;
map <string,int> list,score;
map <int,string> name;
int n,tot,totplayer;
string Name,s;
int Score;
int f[max_n],ch[max_n][2],size[max_n],key[max_n];
int root,sz;
int printtot,printcnt;
inline void clear(int x){
ch[x][0]=ch[x][1]=f[x]=size[x]=key[x]=0;
}
inline bool get(int x){
return ch[ f[x] ][1]==x;
}
inline void update(int x){
if (x){
size[x]=1;
if (ch[x][0]) size[x]+=size[ ch[x][0] ];
if (ch[x][1]) size[x]+=size[ ch[x][1] ];
}
}
inline void rotate(int x){
int old=f[x],oldf=f[old],which=get(x);
ch[old][which]=ch[x][which^1];
f[ ch[old][which] ]=old;
ch[x][which^1]=old;
f[old]=x;
f[x]=oldf;
if (oldf)
ch[oldf][ ch[oldf][1]==old ]=x;
update(old);
update(x);
}
inline void splay(int x,int tar){
for (int fa;(fa=f[x])!=tar;rotate(x))
if (f[fa]!=tar)
rotate( (get(x)==get(fa)) ?fa:x);
if (!tar) root=x;
}
inline int insert(int x){
if (root==0){
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=1;
key[sz]=x;
return sz;
}
int now=root,fa=0;
while(1){
fa=now;
now=ch[now][key[now]<x];
if (now==0){
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz,0);
break;
}
}
return sz;
}
inline int pre(){
int now=ch[root][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
inline void del(int x,int cnt){
splay(cnt,0);
if (!ch[root][0]&&!ch[root][1]){
clear(root);
root=0;
return;
}
if (!ch[root][0]){
int oldroot=root;
root=ch[root][1];
f[root]=0;
clear(oldroot);
return;
}
else if (!ch[root][1]){
int oldroot=root;
root=ch[root][0];
f[root]=0;
clear(oldroot);
return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig,0);
ch[root][1]=ch[oldroot][1];
f[ch[oldroot][1]]=root;
clear(oldroot);
update(root);
}
//返回排名为x的点的编号
inline int findnum(int x){
int now=root,ans;
while (1){
if (ch[now][0]&&x<=size[ ch[now][0] ])
now=ch[now][0];
else{
int temp=1;
if (ch[now][0])
temp+=size[ ch[now][0] ];
if (x<=temp) return now;
x-=temp;
now=ch[now][1];
}
}
}
inline void print(int x){
int now=x;
if (ch[now][1]) print(ch[now][1]);
printtot++;
string s=name[now];
int len=s.length();
for (int i=0;i<len;++i)
putchar(s[i]);
if (printtot!=printcnt) putchar(' ');
if (ch[now][0]) print(ch[now][0]);
}
inline void Query(int L,int R){
int y=totplayer-L+1;
int x=totplayer-(L+R-1)+1;
//x-1 y+1
int aa=findnum(x);
int bb=findnum(y+2);
splay(aa,0);
splay(bb,aa);
printtot=0; printcnt=R;
print( ch[ ch[root][1] ][0] );
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("my.out","w",stdout);
scanf("%d",&n);
insert(-INF);
insert(INF);
for (int i=1;i<=n;++i){
char c=getchar();
while (c!='+'&&c!='?') c=getchar();
//list<string,int>表示名字的编号,score<string,int>表示名字的分数
//name[i]<int,string>表示编号为i的是哪个名字
if (c=='+'){
Name="";
char cc;
while (1){
cc=getchar();
if (cc==' ')
break;
Name=Name+cc;
}
scanf("%d",&Score);
if (list[Name]){
del( score[Name],list[Name] );
score[Name]=Score;
int number=insert( Score );
list[Name]=number;
name[number]=Name;
}
else{
totplayer++;
score[Name]=Score;
int number=insert( Score );
list[Name]=number;
name[number]=Name;
}
}
else{
Name="";
char cc;
while (1){
cc=getchar();
if (cc=='\n') break;
Name+=cc;
}
if (Name[0]>='0'&&Name[0]<='9'){
int Index=0;
int len=Name.length();
for (int j=0;j<len;++j)
Index=Index*10+Name[j]-'0';
int L=Index;
int R=min(totplayer-Index+1,10);
Query(L,R);
putchar('\n');
}
else{//查询玩家排名
splay(list[Name],0);
int ans=size[ ch[root][0] ]-1;
printf("%d\n",totplayer-ans);
}
}
}
return 0;
}
这道题给我的最大的教训是思路一定要简单清晰,要写好写的,否则常数大。
但是通过这道题学会了维护平衡树的两个权好开心(虽然是在TLE的代码里用到了)
调了一天调出来爽啊= =