Codechef Aug2017 #Walks on the binary tree -- 主席樹+Hash
阿新 • • 發佈:2019-01-30
傳送門
每次答案增加的值就是
而與
於是可以用
每個點用主席樹+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;
}