BZOJ 3631 松鼠的新家 树上差分

我猜会有智障说直接链剖+线段树…(希望没有) From RYC's 课件


然鹅我并不反对树剖。。。我是智障。。。QAQ

好吧还是树上差分:设 a[i]=u.a[i+1]=v

++w[u],++w[v],--w[lca(u,v)],--w[fa of lca(u,v)] 最后dfs一边统计答案

#pragma GCC optimize (2)
#include<cstdio>
#include<iostream>
#define R register int
const int M=300010;
using namespace std;
inline int g() {
    R ret=0; register char ch; while(!isdigit(ch=getchar()));
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret;
}
int n,cnt;
int vr[M<<1],nxt[M<<1],fir[M],a[M],d[M],f[M][21],w[M],ans[M];
inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
void dfs(int u) { 
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(d[v]) continue; d[v]=d[u]+1; R p=u; f[v][0]=u;
        for(R j=0;f[p][j];++j) f[v][j+1]=f[p][j],p=f[p][j];
        dfs(v);
    }
}
inline void lca(int u,int v) {
    if(d[u]<d[v]) swap(u,v); R uu=u,vv=v;
    for(R j=20;j>=0;--j) if(d[f[u][j]]>=d[v]) u=f[u][j];
    if(u==v) {--w[u],--w[f[u][0]],++w[uu],++w[vv]; return ;}
    for(R j=20;j>=0;--j) if(f[u][j]!=f[v][j]) u=f[u][j],v=f[v][j];
    u=f[u][0]; ++w[uu],++w[vv],--w[u],--w[f[u][0]]; return ;
}
void dfs2(int u) { 
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==f[u][0]) continue; dfs2(v);
        w[u]+=w[v];
    }
}
signed main() {
    n=g(); for(R i=1;i<=n;++i) a[i]=g();
    for(R i=1,u,v;i<n;++i) u=g(),v=g(),add(u,v),add(v,u);
    d[1]=1; dfs(1); for(R i=1;i<n;++i) lca(a[i],a[i+1]); dfs2(1); 
    for(R i=1;i<=n;++i) printf("%d\n",(i==a[1]?w[i]:w[i]-1));
}

2019.04.22

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/10753156.html