noip 2016 天天爱跑步

从a跑到b

l=lca(a,b)//倍增

用差分的思想要a到b上所经过的点经过次数都+1

那么让从a点+1,b点+1,l点-1,,fa[l][0](l的父亲-1);

如何记录?

一个点a记四个信息(a,t,d,p):

a:起点(如果是从a出发)/终点(如果是从根出发)为a;

t:表示从a出发时间

d:次数+1还是-1;

p:是从a出发到根(0),从根出发到a(1)

我们记录4个点的信息a,b,l,fa[l][0](l的父亲),(记录用邻家链表)

add2(a,0,1,0);
add2(fa[l][0],dep[a]-dep[l]+1,-1,0);//时间为dep之差
add2(b,dep[a]-dep[l]*2,1,1);

add2(l,dep[a]-dep[l]*2,-1,1);

如果检查员在i点,jcy[i]表示在i点的时间

如果是从a出发到根,dep[a]-dep[i]+t=jcy[i],dep[a]+t=jcy[i]+dep[i]

从根出发到a,t+dep[i]=jvy[i],t=jcy[i]-dep[i]

只要满足这个等式就可以被观察到

jcy[i]-dep[i]可能小于0,所以所有等式两边+n(点的总数)

因为a肯定在i的子树里,所以求可以被在a的检查员观察到时是不会影响在i点被观察到的人数的

引进tong1[i](表示从a出发到根,被在i点的检查员观察到的:

tong2[i](表示从根出发到a,被在i点的检查员观察到的:

#include<iostream>
#include<cstdio>
using namespace std;
int ans[300010],n,m,jcy[300010];
int tov[600010],nex[600010],h[300010],tp;
int tpp,nexx[1200010],tod[1200010],top[1200010],tot[1200010],hh[300010];
int tong1[1000010],tong2[1000010];
int dep[300010]={0};  
int fa[300010][20]={0};  
bool vis[300010]={0};  
void add(int x,int y)
{
	tp++;
	nex[tp]=h[x];
	tov[tp]=y;
	h[x]=tp;
}
void add2(int qi,int t,int d,int p)
{
	tpp++;
	nexx[tpp]=hh[qi];
	tod[tpp]=d;
	top[tpp]=p;
	tot[tpp]=t;
	hh[qi]=tpp;
	
}
void dfs(int v)  
{  
  vis[v]=1;  
  for(int i=h[v];i;i=nex[i])  
    if (!vis[tov[i]])  
    {  
      dep[tov[i]]=dep[v]+1;  
      fa[tov[i]][0]=v;  
      dfs(tov[i]);  
    }  
}  
  
int lca(int x,int y)  
{  
  if (dep[x]<dep[y]) swap(x,y);  
  for(int i=19;i>=0;i--)  
    if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];  
  if (x==y) return x;  
  for(int i=19;i>=0;i--)  
    if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];  
  return fa[x][0];  
}  
void solve(int x)
{
   int x1=jcy[x]+dep[x]+n,x2=jcy[x]-dep[x]+n;
   int val1=tong1[x1],val2=tong2[x2];
   for(int i=hh[x];i;i=nexx[i])
   {
   	if(top[i]==0)tong1[tot[i]+dep[x]+n]+=tod[i];
   	else tong2[tot[i]+n]+=tod[i];
   }
   for(int i=h[x];i;i=nex[i])
   {
   	int v=tov[i];
   	if(dep[v]>dep[x])solve(v);
   	}
   	ans[x]=tong1[x1]+tong2[x2]-val1-val2;
}
int main()
{
	//freopen("running.in","r",stdin);
	//freopen("running.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dep[1]=0;dep[0]=-1;  
  dfs(1);  
  for(int i=1;i<=19;i++)  
    for(int j=1;j<=n;j++)  
      fa[j][i]=fa[fa[j][i-1]][i-1];  
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&jcy[i]);
	}
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		int l=lca(a,b);
		add2(a,0,1,0);
		add2(fa[l][0],dep[a]-dep[l]+1,-1,0);
		add2(b,dep[a]-dep[l]*2,1,1);
		add2(l,dep[a]-dep[l]*2,-1,1);
	}
	solve(1);
	for(int i=1;i<=n;i++)
	{
		printf("%d ",ans[i]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Bluelanzhan/article/details/80369103