bzoj3572[HNOI2014]世界树


只说一下大概做法吧,我这个做法好难写(或许有的地方是可以简便的做到的),首先建虚树,把虚树上的"议事处"叫做黑点,其他点叫做白点。
对于每个白点算出最近的黑点以及到它的距离(这个我是dfs一遍用线段树维护深度做的),那么这个白点可以看做那个黑点了,只不过计算距离时要多加一个值,然后dfs一遍,对于虚树上的每条边都计算一下它对两个端点答案的贡献,具体的贡献是原树在这条链上所有的点及其子树。好像不在虚树边上的点答案不好算,于是对于每个黑点把它的初始答案设为它的所有白点siz的最大值(虚树的根的最近的黑点初始答案设为n),枚举每条边时就只需从答案中减去不是黑点控制的即可。
复杂度\(O(logn*\sum m)\)

#include
#include
#include
#include
#include
#include
#include
#define P puts("lala")
#define cp cerr<<"lala"<'9'){if(ch=='-')g=-1; ch=getchar();}
    while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
    return re*g;
}
typedef long long ll;
typedef pair pii;

const int N=300050;
const int inf=0x3f3f3f3f;
int head[N],cnt=0;
struct node
{
    int to,next,w;
}e[N<<1];
inline void add(int x,int y,int w)
{
    e[++cnt]=(node){y,head[x],w};head[x]=cnt;
    e[++cnt]=(node){x,head[y],w};head[y]=cnt;
}
int n,f[N][23],dep[N],m,dfn[N],clk=0,efn[N];
void dfs(int u,int fa,int d)
{
    f[u][0]=fa; dep[u]=d; dfn[u]=++clk;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa) continue;
        dfs(v,u,d+1);
    }
    efn[u]=clk;
}
inline int lca(int x,int y)
{
    if(dep[x]=0;--i) if(d&1<=0;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
inline bool cmp(int a,int b) {return dfn[a]>1;
        build(o<<1,l,mid); build(o<<1|1,mid+1,r);
        minv[o]=min(minv[o<<1],minv[o<<1|1]);
    }
    inline void pushdown(int o)
    {
        if(add[o])
        {
            add[o<<1]+=add[o]; add[o<<1|1]+=add[o];
            minv[o<<1].fi+=add[o]; minv[o<<1|1].fi+=add[o];
            add[o]=0;
        }
    }
    void update(int o,int l,int r,int x,int y,int k)
    {
        if(x<=l&&r<=y) {add[o]+=k; minv[o].fi+=k; return ;}
        pushdown(o);
        int mid=l+r>>1;
        if(x<=mid) update(o<<1,l,mid,x,y,k);
        if(y>mid) update(o<<1|1,mid+1,r,x,y,k);
        minv[o]=min(minv[o<<1],minv[o<<1|1]);
    }
}

int vt[N],tot=0,stk[N],top=0,last[N],dfn2[N],efn2[N],clk2=0,Ans[N];
pii p[N];

inline int getfa(int x,int k)
{
    k=max(k,0);
    for(int i=19;i>=0;--i) if(k&1<efn[stk[top]]) top--;
            add(stk[top],vt[i],dep[vt[i]]-dep[stk[top]]);
            stk[++top]=vt[i];
        }

        clk2=0;
        dfs1(vt[1],0,0);
        seg::build(1,1,tot);
        dfs2(vt[1],0);

        Ans[p[vt[1]].se]=n;
        dfs3(vt[1],0);
        for(int i=1;i<=siz;++i) printf("%d ",Ans[ve[i]]);
        ln;

        for(int i=1;i<=tot;++i) black[vt[i]]=0;
    }
    return 0;
}