• NOIP2016 天天爱跑步 题解


    题目链接

    首先,把每条路径拆成如下两条路径。

    1. 从起点到LCA的路径。
    2. 从LCA到终点的路径。

    对这两条路径分别处理。

    首先,处理从起点到LCA的路径。

    为了方便,我们把这条路径拆成两条,进行差分:

    用从起点到根的路径,减去从LCA到根的路径,得出这条路径的贡献。

    现在我们要处理如下路径:

    从x点出发,走到根,出发时间为t,贡献为g(1或-1)。

    这个操作对点u有贡献,当且仅当满足如下条件:(设sd[x]为x的深度,w[u]表示结点u出现观察员的时间)

    1. x在u的子树中。
    2. t[x]+(sd[x]-sd[u])=w[u] (即sd[u]+w[u]=sd[x]+t[x])。

    所以,开一个数组记录sd[u]+w[u]的出现次数,dfs到u时,用dfs(u)之后的结果-之前的结果,就是u的子树中的x的贡献。(dfs之后比dfs之前仅多包含了u的子树)。

    然后,处理从LCA到终点的路径。

    同样,拆成两条,进行差分。

    我们设从终点为x,起点为根,出发时间为t,贡献为g(1或-1)。

    这个操作对点u有贡献,当且仅当满足如下条件:(设sd[x]为x的深度,w[u]表示结点u出现观察员的时间)

    1. x在u的子树中。
    2. w[u]=sd[u]+t[x] (即w[u]-sd[u]=t[x])。

    同样,开一个数组记录w[u]-sd[u]的出现次数,然后用同样的方法dfs处理。(这里下标有负数,可以通过同时加一个值来解决)。

    代码:

    #include <stdio.h>
    #include <string.h>
    int fr[300010],ne[600010];
    int v[600010],bs=0,mi=0;
    int shu[300010],son[300010];
    int sd[300010],top[300010];
    int fa[300010],W[300010];
    int sl1[1500010],sl2[1500010];
    int sl3[1500010],sl4[1500010];
    int jg[300010],lc[300010];
    struct SLb
    {
    	int he[300010];
    	int r[1200010];
    	int z[1200010];
    	int s;
    	SLb(){s=0;}
    	void addlb(int a,int b)
    	{
    		z[s]=b;
    		r[s]=he[a];
    		he[a]=s;
    		s+=1;
    		if(b<mi)
    			mi=b;
    	}
    };
    SLb lb1,lb2,lb3,lb4;
    void addb(int a,int b)
    {
    	v[bs]=b;
    	ne[bs]=fr[a];
    	fr[a]=bs;
    	bs+=1;
    }
    void dfs1(int u,int f)
    {
    	fa[u]=f;
    	son[u]=-1;
    	shu[u]=1;
    	if(f==-1)
    		sd[u]=0;
    	else
    		sd[u]=sd[f]+1;
    	int ma=0;
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		int t=v[i];
    		if(t!=f)
    		{
    			dfs1(t,u);
    			if(shu[t]>ma)
    			{
    				ma=shu[t];
    				son[u]=t;
    			}
    			shu[u]+=shu[t];
    		}
    	}
    }
    void dfs2(int u,int f,int tp)
    {
    	top[u]=tp;
    	if(son[u]==-1)
    		return;
    	dfs2(son[u],u,tp);
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		if(v[i]!=f&&v[i]!=son[u])
    			dfs2(v[i],u,v[i]);
    	}
    }
    int lca(int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		if(sd[top[x]]>sd[top[y]])
    			x=fa[top[x]];
    		else
    			y=fa[top[y]];
    	}
    	return sd[x]<sd[y]?x:y;
    }
    void dfs3(int u,int f)
    {
    	int yq=W[u]-sd[u]+mi;
    	int j=(yq<0?0:sl1[yq]);
    	for(int i=lb1.he[u];i!=-1;i=lb1.r[i])
    		sl1[lb1.z[i]+mi]+=1;
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		if(v[i]!=f)
    			dfs3(v[i],u);
    	}
    	j=(yq<0?0:sl1[yq])-j;
    	jg[u]+=j;
    }
    void dfs4(int u,int f)
    {
    	int yq=W[u]+sd[u]+mi;
    	int j=(yq<0?0:sl2[yq]);
    	for(int i=lb2.he[u];i!=-1;i=lb2.r[i])
    		sl2[lb2.z[i]+sd[u]+mi]+=1;
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		if(v[i]!=f)
    			dfs4(v[i],u);
    	}
    	j=(yq<0?0:sl2[yq])-j;
    	jg[u]+=j;
    }
    void dfs5(int u,int f)
    {
    	int yq=W[u]-sd[u]+mi;
    	int j=(yq<0?0:sl3[yq]);
    	for(int i=lb3.he[u];i!=-1;i=lb3.r[i])
    		sl3[lb3.z[i]+mi]+=1;
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		if(v[i]!=f)
    			dfs5(v[i],u);
    	}
    	j=(yq<0?0:sl3[yq])-j;
    	jg[u]-=j;
    }
    void dfs6(int u,int f)
    {
    	int yq=W[u]+sd[u]+mi;
    	int j=(yq<0?0:sl4[yq]);
    	for(int i=lb4.he[u];i!=-1;i=lb4.r[i])
    		sl4[lb4.z[i]+sd[u]+mi]+=1;
    	for(int i=fr[u];i!=-1;i=ne[i])
    	{
    		if(v[i]!=f)
    			dfs6(v[i],u);
    	}
    	j=(yq<0?0:sl4[yq])-j;
    	jg[u]-=j;
    }
    int main()
    {
    	int N,M;
    	scanf("%d%d",&N,&M);
    	for(int i=1;i<=N;i++)
    		fr[i]=lb1.he[i]=lb2.he[i]=lb3.he[i]=lb4.he[i]=-1;
    	for(int i=0;i<N-1;i++)
    	{
    		int a,b;
    		scanf("%d%d",&a,&b);
    		addb(a,b);
    		addb(b,a);
    	}
    	dfs1(1,-1);
    	dfs2(1,-1,1);
    	for(int i=1;i<=N;i++)
    		scanf("%d",&W[i]);
    	for(int i=0;i<M;i++)
    	{
    		int S,T;
    		scanf("%d%d",&S,&T);
    		lc[i]=lca(S,T);
    		lb2.addlb(S,0);
    		lb4.addlb(lc[i],sd[S]-sd[lc[i]]);
    		lb1.addlb(T,sd[S]-sd[lc[i]]*2);
    		lb3.addlb(lc[i],sd[S]-sd[lc[i]]*2);
    		if(W[lc[i]]==sd[S]-sd[lc[i]])
    			jg[lc[i]]+=1;
    	}
    	mi=-mi;
    	dfs3(1,-1);
    	dfs4(1,-1);
    	dfs5(1,-1);
    	dfs6(1,-1);
    	for(int i=1;i<=N;i++)
    		printf("%d ",jg[i]);
    	return 0;
    }
    
  • 相关阅读:
    [WM]谁抢走了应用程序的性能?
    只有更烂的程序员
    [WM]n久以前写的ConnMgr类
    [WM][转]PPC中如何找到正在使用中的网络(源代码)
    让IE6支持minwidth和maxwidth的方法(JS实现) + (CSS实现)
    jQuery tab 切换函数
    wap、3g手机的端的网页头部
    复制到系统剪贴板之IE,ff兼容版
    鼠标滑过展开,js版和jquery版
    JS+CSS实现网页滚动条美化
  • 原文地址:https://www.cnblogs.com/lnzwz/p/11246699.html
Copyright © 2020-2023  润新知