需要的功能:
①更新一个字符串对应的最新分数
②获得一个字符串对应的最新分数
③获得平衡树中第几名
hint是哈希,感觉没什么头绪。。
题解存下了字符串和一个哈希内存池,用链式前向星处理hash冲突,用时间戳作为第二比较关键字,在分数相同时检索时间戳
具体来说就是在查询一个字符串时,先在哈希内存池顺着前向星用字符串匹配找到时间戳,
再用分数和时间戳的关键字从treap中找到对应信息(适合题目的较早信息有高rank的设定)
这题核心就在于把时间戳作为第二关键字的运用可以实现简单的map,以及哈希内存池的设置,这些在以前我都没见过。。
#include<bits/stdc++.h> //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; #define ll long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) const int inf=0x3f3f3f3f; const int maxn=2e5+5e4+9; const int mod=985003; int n; int root,sz,tot,head[mod+1]; struct data1{int v,time,nxt;char ch[10];}hash[maxn]; struct data2{int l,r,v,s,rnd,time;char ch[10];}tr[maxn]; void update(int k){tr[k].s=tr[tr[k].l].s+tr[tr[k].r].s+1;} void rturn(int &k){int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;tr[t].s=tr[k].s;update(k);k=t;} void lturn(int &k){int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;tr[t].s=tr[k].s;update(k);k=t;} bool cmp(char a[],char b[]){for(int i=1;i<max(strlen(a),strlen(b));i++)if(a[i]!=b[i])return 0;return 1;} int Hash(char ch[]){ int s=0; for(int i=1;i<strlen(ch);i++) {s*=27;s+=(ch[i]-'A'+1);s%=mod;} return s; } void del(int &k,int x,int time){ if(tr[k].v==x){ if(tr[k].time==time){ if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r; else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd){rturn(k);del(k,x,time);} else {rturn(k);del(k,x,time);} } else if(time>tr[k].time){tr[k].s--;del(tr[k].l,x,time);} else {tr[k].s--;del(tr[k].r,x,time);} } else if(x<tr[k].v){tr[k].s--;del(tr[k].l,x,time);} else {tr[k].s--;del(tr[k].r,x,time);} } void insert(int &k,char ch[],int x,int time){ if(k==0){ sz++;k=sz;tr[k].v=x;tr[k].s=1;tr[k].rnd=rand(); memcpy(tr[k].ch,ch,strlen(ch));tr[k].time=time; return; } tr[k].s++; if(x<=tr[k].v){insert(tr[k].l,ch,x,time);if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);} //小于等于都放在左儿子,所以时间大在左边 else{insert(tr[k].r,ch,x,time);if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);} } void INS(char ch[],int x,int time){ //hash[i]存储hash值为i的尾指针 int k=Hash(ch);int i=head[k]; while(i){ if(cmp(hash[i].ch,ch)){ //在冲突的哈希中检测同名,更新记录 del(root,hash[i].v,hash[i].time); hash[i].time=time;hash[i].v=x; insert(root,ch,x,time); return; } i=hash[i].nxt; } tot++; //给新的玩家分配一个节点 hash[tot].time=time;hash[tot].v=x; memcpy(hash[tot].ch,ch,strlen(ch)); hash[tot].nxt=head[k];head[k]=tot; insert(root,ch,x,time); } int get(char ch[]){ //获取字符串在hash[]数组中的下标 int k=Hash(ch);int i=head[k]; while(i){ if(cmp(hash[i].ch,ch))return i; i=hash[i].nxt; } } int getrank(int k,int x,int time){ if(k==0)return 0; if(tr[k].v==x){ if(tr[k].time>time)return getrank(tr[k].r,x,time); else if(tr[k].time<time)return 1+tr[tr[k].r].s+getrank(tr[k].l,x,time); //先传记录优先 else return tr[tr[k].r].s+1; } else if(tr[k].v<x)return getrank(tr[k].r,x,time); else return 1+tr[tr[k].r].s+getrank(tr[k].l,x,time); } void ask1(char ch[]){ //询问排名 int t=get(ch); printf("%d ",getrank(root,hash[t].v,hash[t].time)); } int index(int k,int x){ //获得第x名的树节点编号 if(tr[tr[k].r].s+1==x)return k; else if(x<=tr[tr[k].r].s)return index(tr[k].r,x); else return index(tr[k].l,x-tr[tr[k].r].s-1); } void ask2(char ch[]){ int s=0; for(int i=1;i<strlen(ch);i++){s*=10;s+=ch[i]-'0';} for(int i=s;i<=tot&&i<=s+9;i++){ printf("%s",tr[index(root,i)].ch+1); if(i<tot&&i<s+9)printf(" "); } printf(" "); } int main(){ scanf("%d",&n);char ch[11];int x; for(int i=1;i<=n;i++){ scanf("%s",ch); if(ch[0]=='+'){scanf("%d",&x);INS(ch,x,i);} else if(ch[1]>='A'&&ch[1]<='Z')ask1(ch); else ask2(ch); } }