【SHOI2014/Luogu4332】三叉神经树 树链剖分

原题走这里

首先我们定义节点的状态0,1,2,3分别代表该节点分别接收到0,1,2,3个信号。
那么我们会发现,叶子节点的状态改变,会导致叶子节点到根的路径上一连串节点的状态改变。
比如当某叶子节点到根的路径上,
由叶子节点开始的若干个连续的节点均处于状态2,且该叶子节点处于激活状态,
那么此时,如果我们改变这一叶子节点的状态,
则从叶子节点开始,一路向根走,遇到的这些连续的2节点全部会变成状态1,
此外还要对应更新最后一个2节点的父节点。

因此,我们实质上就是要实现以下操作(单点修改之类的就不算了):
1.查询从根到某叶节点有多少个从叶节点开始的连续的1节点或2节点
2.把这些节点变成状态1或2

恩,于是我们可以树链剖分,用线段树维护本区间最右节点的状态,以及从本区间右端点开始有多少个连续的状态1或状态2节点即可。

具体细节见代码如下:
为什么我的代码这么慢啊

#include 
using namespace std;
char buf[25000000],*pp=buf;
#define getchar() *(pp++)
inline int read() {
    int X=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')w=(ch=='-'?-1:1),ch=getchar();
    while(ch>='0'&&ch<='9')X=X*10+ch-'0',ch=getchar();
    return X*w;
}
struct edge {
    int v,p;
    inline edge(int _v=0,int _p=0) {
        v=_v;
        p=_p;
    }
} e[3000010];
int n,q,head[1500010],top,sr[6000010],siz[1500010],dep[1500010],w[1500010],tp[1500010],f[1500010],son[1500010],m,s[1500010],st[6000010],lazy[6000010];
inline void addedge(int u,int v) {
    e[++top]=edge(v,head[u]);
    head[u]=top;
    e[++top]=edge(u,head[v]);
    head[v]=top;
}
void dfs1(int u,int fa) {
    siz[u]=1;
    f[u]=fa;
    for(int i=head[u]; i; i=e[i].p) {
        int v=e[i].v;
        if(v==fa)continue;
        dep[e[i].v]=dep[u]+1;
        dfs1(v,u);
        siz[u]+=siz[v];
        f[v]=u;
        if(siz[son[u]]void dfs2(int u,int t) {
    w[u]=++m;
    tp[u]=t;
    if(son[u])dfs2(son[u],t);
    for(int i=head[u]; i; i=e[i].p) {
        int v=e[i].v;
        if(v==f[u]||v==son[u])continue;
        dfs2(v,v);
    }
}
int dfs3(int u) { 
    if(s[w[u]]>=0)return s[w[u]];
    int ret=-1;
    for(int i=head[u]; i; i=e[i].p) {
        int v=e[i].v;
        if(v==f[u])continue;
        ret+=dfs3(v)>0;
    }
    return s[w[u]]=ret;
}
inline void push_down(int k,int l,int r) {
    if(l!=r&&lazy[k]>=0) {
        int mid=(l+r)>>1;
        lazy[k<<1]=lazy[k<<1|1]=lazy[k];
        sr[k<<1]=mid-l+1;
        sr[k<<1|1]=r-mid;
        st[k<<1]=st[k<<1|1]=lazy[k];
    }
    lazy[k]=-1;
}
inline void update(int k,int l,int r) {
    int mid=(l+r)>>1;
    st[k]=st[k<<1|1];
    if(st[k]==0||st[k]==1) {
        sr[k]=sr[k<<1|1];
        if(sr[k]==r-mid&&st[k]==st[k<<1]) {
            sr[k]+=sr[k<<1];
        }
    } else {
        sr[k]=0;
    }
}
void build(int k,int l,int r) {
    if(l==r) {
        st[k]=s[l];
        if(s[l]==0||s[l]==1)sr[k]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    update(k,l,r);
}
int query(int x) {
    int k=1;
    for(int l=1,r=m;l^r;)
    {
        push_down(k,l,r);
        int mid=(l+r)>>1;
        if(x<=mid)k=(k<<1),r=mid;
        else k=(k<<1|1),l=mid+1;
    }
    return st[k];
}
int ask(int k,int l,int r,int L,int R,bool x) {
    push_down(k,l,r);
    if(L==l&&r==R) {
        return st[k]==x?sr[k]:0;
    }
    int mid=(l+r)>>1,r1,r2;
    if(R<=mid) {
        return ask(k<<1,l,mid,L,R,x);
    } else if(L>mid) {
        return ask(k<<1|1,mid+1,r,L,R,x);
    } else {
        r2=ask(k<<1|1,mid+1,r,mid+1,R,x);
        r1=ask(k<<1,l,mid,L,mid,x);
        return r2==(R-mid)?r2+r1:r2;
    }
}
void work(int k,int l,int r,int L,int R,int x) {
    push_down(k,l,r);
    if(L<=l&&r<=R) {
        lazy[k]=x;
        sr[k]=r-l+1;
        st[k]=x;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) {
        work(k<<1,l,mid,L,R,x);
    }
    if(R>mid) {
        work(k<<1|1,mid+1,r,L,R,x);
    }
    update(k,l,r);
}
void work(int k,int l,int r,int x,bool y) {
    push_down(k,l,r);
    if(l==r) {
        st[k]+=y?1:-1;
        sr[k]=(st[k]==0||st[k]==1);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) {
        work(k<<1,l,mid,x,y);
    } else {
        work(k<<1|1,mid+1,r,x,y);
    }
    update(k,l,r);
}
void change(int x,bool y) {
    for(register int t; x; x=f[tp[x]]) {
        t=ask(1,1,m,w[tp[x]],w[x],y^1);
        if(!t) {
            work(1,1,m,w[x],y);
            break;
        }
        work(1,1,m,w[x]-t+1,w[x],y);
        if(t<=w[x]-w[tp[x]])
        {
            work(1,1,m,w[x]-t,y);
            break;
        }
    }
}
int main() {
    fread(buf,sizeof(char),sizeof(buf),stdin);
    memset(lazy,-1,sizeof(lazy));
    memset(s,-1,sizeof(s));
    n=read();
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=3; j++) {
            addedge(i,read());
        }
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=n+1; i<=3*n+1; i++) {
        s[w[i]]=read();
    }
    dfs3(1);
    build(1,1,m);
    q=read();
    for(int i=1,x,y; i<=q; i++) {
        x=read();
        y=query(w[x]);
        change(x,y^1);
        putchar((int)(query(1)>0)+'0');
        putchar('\n');
    }
    return 0;
}

你可能感兴趣的:(【SHOI2014/Luogu4332】三叉神经树 树链剖分)