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\n",ans);
    	while(qt>1) va[qto[qt]]=-1,qhd[qto[qt]]=0,--qt;
    	va[1]=-1,qhd[1]=0;
    }
    return 0;
}
posted @ 2020-02-22 17:38  ✡smy✡  阅读(327)  评论(3编辑  收藏  举报