替罪羊树模板(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 newadd; 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; newadd=1; 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); newadd=0; int po=hash_query(nam); if (!newadd) { 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"); } } }