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

来源:互联网 发布:五金淘宝店铺表示 编辑:程序博客网 时间:2024/05/29 05:07

传送门

每次答案增加的值就是 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 1000000009struct 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;}
阅读全文
0 0
原创粉丝点击