# 替罪羊树模板（BZOJ1056/1862）

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#define LL long long
#define LDB long double
using namespace std;

LDB alpha=0.75;
const LL mo=3000001;
int root=1,datcnt,rbcnt,cnt,nodeintree,delnode;
char ans[20];
int nd[3000001],nex[3000001];
int rb[600001];
LL key[3000001];

struct treenode{
int size,lc,rc,num,fa,tim,v,dep;
LL nam;

inline bool operator < (const treenode&a) const {
if (num<a.num) return(1);
if (num>a.num) return(0);
if (tim>a.tim) return(1);
return(0);
}

inline bool operator == (const treenode&a) const{
if ((a.num==num)&&(a.tim==tim)&&(a.nam==nam)) return(1);
return(0);
}
}tr[600001],dat[600001];

LL namhash(char* st){
LL t=0,len=strlen(st);
for (int i=1;i<len;i++)
t*=27,t+=st[i]-'A'+1;
return(t);
}

int numget(char* st){
int t=0,len=strlen(st);
for (int i=1;i<len;i++) t*=10,t+=st[i]-'0';
return(t);
}

void namtrans(LL nam){
int cnt=-1;LL t=1;
while (t<=nam)
t*=27,cnt+=1;

for (int i=cnt;i>=0;i--) ans[i]=nam%27+'A'-1,nam/=27;
for (int i=0;i<=cnt;i++) putchar(ans[i]);
}

int hash_query(LL nam){
int po=nam%mo;
for (int p=nd[po];p!=-1;p=nex[p])
if (key[p]==nam) return(p);
nex[++datcnt]=nd[po];nd[po]=datcnt;key[datcnt]=nam;
return(datcnt);
}

int getrank(int po,treenode t){
if ((t==tr[po])&&(tr[po].v!=0)) return(tr[tr[po].lc].size+tr[po].v);
if (t<tr[po]) return(getrank(tr[po].lc,t));
if (tr[po]<t) return(getrank(tr[po].rc,t)+tr[tr[po].lc].size+tr[po].v);
}

LL getkth(int po,int num){
if (num<=tr[tr[po].lc].size) return(getkth(tr[po].lc,num));
if (num>tr[tr[po].lc].size+tr[po].v) return(getkth(tr[po].rc,num-tr[tr[po].lc].size-tr[po].v));
return(tr[po].nam);
}

void dfs(int po){
if (tr[po].lc) dfs(tr[po].lc);
if (tr[po].v) rb[++rbcnt]=po;else nodeintree--,delnode--;
if (tr[po].rc) dfs(tr[po].rc);
}

void build(int l,int r){
int mid=(l+r)>>1,po=rb[(l+r)/2];

if (l<mid){
tr[po].lc=rb[(l+mid-1)/2];
tr[rb[(l+mid-1)/2]].fa=po;
tr[rb[(l+mid-1)/2]].dep=tr[po].dep+1;
build(l,mid-1);
}else tr[po].lc=0;
if (r>mid){
tr[po].rc=rb[(r+mid+1)/2];
tr[rb[(r+mid+1)/2]].fa=po;
tr[rb[(r+mid+1)/2]].dep=tr[po].dep+1;
build(mid+1,r);
}else tr[po].rc=0;
tr[po].size=tr[tr[po].lc].size+tr[tr[po].rc].size+tr[po].v;
}

void rebuild(int po){
rbcnt=0;dfs(po);

if (po!=root){
tr[rb[(rbcnt+1)/2]].fa=tr[po].fa;
tr[rb[(rbcnt+1)/2]].dep=tr[tr[po].fa].dep+1;
if (po==tr[tr[po].fa].lc) tr[tr[po].fa].lc=rb[(rbcnt+1)/2];
else tr[tr[po].fa].rc=rb[(rbcnt+1)/2];
}else {root=rb[(rbcnt+1)/2];tr[rb[(rbcnt+1)/2]].fa=0;tr[rb[(rbcnt+1)/2]].dep=0;}

build(1,rbcnt);
}

void scapegoat_insert(int num){
nodeintree++;
if ((tr[root].size==0)&&(tr[root].lc==0)&&(tr[root].rc==0)) {
root=++cnt;tr[root]=dat[num];tr[root].dep=0;
tr[cnt].v=1;tr[cnt].size=1;
return;
}
int po=root;
while (1){
tr[po].size++;

if (dat[num]==tr[po]) {tr[po].v++;break;}

if (dat[num]<tr[po]){
if (tr[po].lc==0){
tr[++cnt]=dat[num];
tr[cnt].fa=po;
tr[po].lc=cnt;
tr[cnt].dep=tr[po].dep+1;
tr[cnt].v=1;tr[cnt].size=1;
break;
}else {po=tr[po].lc;continue;}
}

if (tr[po]<dat[num]){
if (tr[po].rc==0){
tr[++cnt]=dat[num];
tr[cnt].fa=po;
tr[po].rc=cnt;
tr[cnt].dep=tr[po].dep+1;
tr[cnt].v=1;tr[cnt].size=1;
break;
}else {po=tr[po].rc;continue;}
}
}

if (tr[po].dep>(log(tr[root].size)/log(1/alpha))){
int dp=tr[po].dep;
while ((dp-tr[po].dep)<=(log(tr[po].size)/log(1/alpha))) po=tr[po].fa;
rebuild(po);
}
}

void scapegoat_delete(int num){
int po=root;
while (1){
tr[po].size--;
if (tr[po]<dat[num]) {po=tr[po].rc;continue;}
if (dat[num]<tr[po]) {po=tr[po].lc;continue;}
if (tr[po]==dat[num]) {tr[po].v--;if (tr[po].v==0) delnode++;break;}
}
if (delnode>nodeintree/2) rebuild(root);
}

int main(){

freopen("a.in","r",stdin);

int n;char st[20];
scanf("%d",&n);

for (int i=0;i<=3000000;i++) nd[i]=-1;

for (int i=1;i<=n;i++){
scanf("%s",st);

if (st[0]=='+'){
LL nam=namhash(st);
int po=hash_query(nam);
scapegoat_delete(po);
dat[po].nam=nam;scanf("%d",&dat[po].num);dat[po].tim=i;
scapegoat_insert(po);
}else{
dat[po].nam=nam;scanf("%d",&dat[po].num);dat[po].tim=i;
scapegoat_insert(po);
}
}

if ((st[0]=='?')&&(st[1]<='Z')&&(st[1]>='A')){
LL nam=namhash(st);
int po=hash_query(nam);
printf("%d\n",datcnt-getrank(root,dat[po])+1);
}

if ((st[0]=='?')&&(st[1]<='9')&&(st[1]>='0')){
int po=numget(st);
for (int i=po;i<=min(po+9,datcnt);i++) {
namtrans(getkth(root,datcnt-i+1));
if (i!=min(po+9,datcnt))printf(" ");
}
printf("\n");
}
}
}

posted @ 2016-06-23 14:19  z1j1n1  阅读(161)  评论(0编辑  收藏  举报