1. 程式人生 > >Codechef Aug2017 #Walks on the binary tree -- 主席樹+Hash

Codechef Aug2017 #Walks on the binary tree -- 主席樹+Hash

傳送門

每次答案增加的值就是 n - 之前出現的數與 XLCP 最大值。
而與 XLCP 最大的點在 dfs 序上與 X 的距離最近。而在滿二叉樹上 Xdfs 序上的位置就等於 X
於是可以用 set 維護所有出現過的點,加入 X 時找 X 兩邊最近的點更新答案。
每個點用主席樹+hash維護。

程式碼

#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace
std; #define N 100010 #define P1 127 #define P2 233 #define M1 1000000007 #define M2 1000000009 struct Hash{ int s1,s2; Hash(int s1=0,int s2=0):s1(s1),s2(s2){} bool operator == (Hash a)const{ return s1==a.s1&&s2==a.s2; } Hash operator + (Hash a)const{ return Hash((s1+a.s1)%M1,(s2+a.s2)%M2); } Hash operator
* (int p)const{ return Hash(s1*p,s2*p); } }; typedef Hash ull; struct Node{ int l,r,p,s; ull w; }c[N*75]; int h1[N],h2[N],s1[N],s2[N]; int i,j,k,n,m,p,T,Q,Num,x,Cur; long long Ans; char ss[2]; inline void Up(int x){ c[x].s=c[c[x].l].s+c[c[x].r].s; c[x].w=c[c[x].l].w+c[c[x].r].w; } inline
void Ch(int& x,int y,int p,int l,int r){ x=++Num; c[x].l=c[y].l;c[x].r=c[y].r; c[x].p=p; c[x].w=Hash((s1[r]-s1[l-1]+M1)%M1,(s2[r]-s2[l-1]+M2)%M2)*p; c[x].s=(r-l+1)*p; } inline void Down(int x,int l,int r){ if(c[x].p!=-1){ int Mid=l+r>>1; Ch(c[x].l,c[x].l,c[x].p,l,Mid);Ch(c[x].r,c[x].r,c[x].p,Mid+1,r); c[x].p=-1; } } inline bool Query(int x,int l,int r,int y){ if(!x)return 0; Down(x,l,r); if(l==r)return c[x].s; int Mid=l+r>>1; if(y<=Mid)return Query(c[x].l,l,Mid,y); return Query(c[x].r,Mid+1,r,y); } inline void Insert(int& x,int y,int l,int r,int L,int R,int p){ if(l>R||r<L)return; Down(x,l,r); if(l>=L&&r<=R){ Ch(x,y,p,l,r); return; } x=++Num;c[x].l=c[y].l;c[x].r=c[y].r;c[x].p=-1; int Mid=l+r>>1; Insert(c[x].l,c[y].l,l,Mid,L,R,p); Insert(c[x].r,c[y].r,Mid+1,r,L,R,p); Up(x); } inline int Find(int x,int l,int r,int y){ if(l==r)return c[x].s?-1:l; Down(x,l,r); int Mid=l+r>>1; if(l>=y){ if(c[c[x].l].s<Mid-l+1)return Find(c[x].l,l,Mid,y); return Find(c[x].r,Mid+1,r,y); } if(y>Mid)return Find(c[x].r,Mid+1,r,y); int t=Find(c[x].l,l,Mid,y); return t==-1?Find(c[x].r,Mid+1,r,y):t; } inline void Update(int& x,int z){ bool t=Query(x,1,n,z); if(!t)Insert(x,x,1,n,z,z,1);else{ int p=Find(x,1,n,z); if(p==-1)p=n+1; Insert(x,x,1,n,z,p-1,0); if(p<=n)Insert(x,x,1,n,p,p,1); } } inline bool Check(int x,int y,int l,int r){ if(!c[y].s)return 0; if(!c[x].s)return 1; Down(x,l,r);Down(y,l,r); if(l==r)return 0; int Mid=l+r>>1; if(c[c[x].r].w==c[c[y].r].w)return Check(c[x].l,c[y].l,l,Mid); return Check(c[x].r,c[y].r,Mid+1,r); } inline int Get(int x,int y,int l,int r){ if(x)Down(x,l,r); if(y)Down(y,l,r); if(l==r)return l; int Mid=l+r>>1; if(c[c[x].r].w==c[c[y].r].w)return Get(c[x].l,c[y].l,l,Mid); return Get(c[x].r,c[y].r,Mid+1,r); } struct D{ int x; D(int x=0):x(x){} bool operator < (D y)const{ return Check(x,y.x,1,n); } }t; set<D>S; set<D>::iterator It; int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&Q); Num=Cur=0;Ans=1;S.clear();c[0].p=-1; h1[0]=h2[0]=1; for(i=1;i<=n;i++)h1[i]=1ll*h1[i-1]*P1%M1,h2[i]=1ll*h2[i-1]*P2%M2,s1[i]=(h1[i]+s1[i-1])%M1,s2[i]=(h2[i]+s2[i-1])%M2; while(Q--){ scanf("%s",ss); if(ss[0]=='?')printf("%lld\n",Ans);else{ scanf("%d",&x);x++; Update(Cur,x); t=D(Cur); if(S.find(t)!=S.end())continue; It=S.insert(t).first; m=n; It++; if(It!=S.end())m=Get(Cur,It->x,1,n); It--; if(It!=S.begin()){ It--; m=min(m,Get(Cur,It->x,1,n)); } Ans+=m; } } } return 0; }