• CodeChef BTREE Union on Tree


    vj

    这题的数据限制不难想到要套一个虚树.对于一个询问,我们先把包含所有关键点的虚树建出来,然后预处理虚树上每个点的最大覆盖范围,具体操作是一遍dfs由儿子更新父亲, 即(va_x=max(va_x,va_y-dis_{x,y})) ,第二遍dfs由父亲更新儿子.那么现在要解决两个问题:怎么统计一个点的贡献,怎么减掉算重的部分

    先考虑只统计一个点的贡献,本能的想法是预处理出到某个点距离 (le) 某个值的点数.因为到某个点距离 (le) 某个值的那些点在树上是个连通块,所以建出点分树,然后预处理每个点在点分子树内深度 (le) 某个值的点数 (f_{x,j}) ,和这个点的点分子树在点分树上父亲的点分子树里的(到点分父亲)深度 (le) 某个值的点数 (g_{x,j}) ,每次从询问点开始跳点分树父亲,假设我们询问距离点 (u) 不超过 (l) 的点数,设当前点为 (x) ,上一个点为 (ls) ,那么 (x) 的贡献为 (f_{x,l-dis_{u,x}}-g_{ls,l-dis_{u,x}})

    然后是关于算重部分,因为经过上面一个预处理,对于虚树上相邻两点,他们算重部分连通块的中心一定在这两个点之间,并且每两个点的算重部分和其他点没有关系,所以只要减去每两个点的算重部分即可.可以发现这部分也是距离一个点不超过某个值的一个连通块,可以用一样的方法统计

    注意这个点可能在边上,所以把所有边当成点即可,同时读入的覆盖范围要乘2

    #include<bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    const int N=114514;
    LL rd()
    {
        LL x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[N<<1],nt[N<<1],hd[N],tot=1;
    void adde(int x,int y)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
    }
    int qto[N<<1],qnt[N<<1],qhd[N],qt=1;
    void addq(int x,int y)
    {
        ++qt,qto[qt]=y,qnt[qt]=qhd[x],qhd[x]=qt;
        ++qt,qto[qt]=x,qnt[qt]=qhd[y],qhd[y]=qt;
    }
    int n,lz,dfn[N],ti,fa[N][20],gfa[N],ps[N],gds[N][50],rt,nsz,mx,sz[N],de[N],dp[N],t1[N],t2[N];
    bool cmp(int aa,int bb){return dfn[aa]<dfn[bb];}
    void dfs1(int x)
    {
        dfn[x]=++ti;
        for(int j=1;j<=lz;++j)
        {
    	    fa[x][j]=fa[fa[x][j-1]][j-1];
    	    if(!fa[x][j]) break;
        }
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==fa[x][0]) continue;
        	fa[y][0]=x,de[y]=de[x]+1,dfs1(y);
        }
    }
    int glca(int x,int y)
    {
        if(de[x]<de[y]) swap(x,y);
        for(int j=lz;~j;--j) if(de[fa[x][j]]>=de[y]) x=fa[x][j];
        if(x==y) return x;
        for(int j=lz;~j;--j) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
        return fa[x][0];
    }
    int gdis(int x,int y){return de[x]+de[y]-2*de[glca(x,y)];}
    bool ban[N];
    vector<int> f[N],g[N];
    void fdrt(int x,int ffa)
    {
        int nv=0;
        sz[x]=1,dp[x]=de[x];
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==ffa||ban[y]) continue;
        	de[y]=de[x]+1,fdrt(y,x);
        	dp[x]=max(dp[x],dp[y]),sz[x]+=sz[y],nv=max(nv,sz[y]);
        }
        nv=max(nv,nsz-sz[x]);
        if(nv<mx) mx=nv,rt=x;
    }
    void dfs2(int x,int ffa,int xx,int ln)
    {
        g[xx][ln]+=x<=n;
        gds[x][++ps[x]]=ln;
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==ffa||ban[y]) continue;
        	dfs2(y,x,xx,ln+1);
        }
    }
    int bui(int x)
    {
        mx=nsz+1,fdrt(x,0),x=rt,ban[x]=1;
        de[x]=0,fdrt(x,0);
        f[x].resize(t1[x]=dp[x]+1),f[x][0]=x<=n;
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(ban[y]) continue;
        	nsz=sz[y];//少了这行又WA又T
        	int len=dp[y]+1,yy=bui(y);
        	t2[yy]=len,gfa[yy]=x;
        	g[yy].resize(t2[yy]),dfs2(y,x,yy,1);
        	for(int j=1;j<t2[yy];++j) f[x][j]+=g[yy][j],g[yy][j]+=g[yy][j-1];
        }
        for(int j=1;j<t1[x];++j) f[x][j]+=f[x][j-1];
        ban[x]=0;
        return x;
    }
    int cal(int x,int l)
    {
        if(l<0) return 0;
        int xx=x,ls=0,ans=0;
        for(int j=0;x;++j)
        {
        	int nl=min(t1[x]-1,l-gds[xx][j]);
        	if(nl>=0) ans+=f[x][nl]-(t2[ls]?g[ls][min(t2[ls]-1,nl)]:0);
        	ls=x,x=gfa[x];
        }
        return ans;
    }
    int va[N],st[N],tp,sq[N],ts,ans;
    void dd1(int x,int ffa)
    {
        for(int i=qhd[x];i;i=qnt[i])
        {
        	int y=qto[i];
        	if(y==ffa) continue;
        	dd1(y,x),va[x]=max(va[x],va[y]-(de[y]-de[x]));
        }
    }
    void dd2(int x,int ffa)
    {
        ans+=cal(x,va[x]);
        for(int i=qhd[x];i;i=qnt[i])
        {
        	int y=qto[i];
        	if(y==ffa) continue;
        	int ln=de[y]-de[x];
        	va[y]=max(va[y],va[x]-ln),nsz=sz[y],dd2(y,x);
        	int zl=va[x]>=va[y]?va[x]-(ln-(va[y]-va[x]))/2:va[y]-(ln-(va[x]-va[y]))/2;
        	int xx=y,rs=va[y]-zl;
        	for(int j=lz;~j;--j) if(rs>=(1<<j)) rs-=1<<j,xx=fa[xx][j];
        	ans-=cal(xx,zl);
        }
    }
    
    int main()
    {
        n=rd(),lz=log2(n<<1);
        for(int i=1;i<n;++i) adde(n+i,rd()),adde(n+i,rd());
        nsz=n+n-1,rt=bui(1);
        de[1]=1,dfs1(1);
        memset(va,-1,sizeof(va));
        int q=rd();
        while(q--)
        {
        	ts=rd();
        	for(int i=1;i<=ts;++i)
        	    sq[i]=rd(),va[sq[i]]=rd()<<1;
        	sort(sq+1,sq+ts+1,cmp);
        	st[tp=1]=1;
        	for(int i=1+(sq[1]==1);i<=ts;++i)
        	{
        	    int x=sq[i],lca=glca(x,st[tp]);
        	    if(lca!=st[tp]) 
        	    {
            		while(tp>1&&dfn[st[tp-1]]>=dfn[lca]) addq(st[tp],st[tp-1]),--tp;
            		while(dfn[st[tp]]>dfn[lca]) addq(st[tp],lca),--tp;
            		if(st[tp]!=lca) st[++tp]=lca;
        	    }
        	    st[++tp]=x;
        	}
        	while(tp>1) addq(st[tp],st[tp-1]),--tp;
        	dd1(1,0);
        	ans=0,dd2(1,0);
        	printf("%d
    ",ans);
        	while(qt>1) va[qto[qt]]=-1,qhd[qto[qt]]=0,--qt;
        	va[1]=-1,qhd[1]=0;
        }
        return 0;
    }
    
  • 相关阅读:
    记一次MD5妙用
    go执行外部应用
    Go语言中的HTTP
    Go语言中的UDP应用
    Go学习
    Element-ui学习使用
    Vue学习
    BootCDNApi使用记录
    jquery.easypiechart.js简介
    jquery.gritter.js简介
  • 原文地址:https://www.cnblogs.com/smyjr/p/12346351.html
Copyright © 2020-2023  润新知