zoukankan      html  css  js  c++  java
  • 天天爱跑步

    题目传送门

    借鉴的大佬的博客这儿
    个人认为我的解释更详细一些

    先来看部分分

    $1.$25分

    (当然是大暴力了!)

    (2.)一条链

    首先,要考虑到它有左往右和从右往左两种情况
    这里只讨论从左往右的情况,从右往左类似。

    若第(i)条路径对(u)点有贡献,当且仅当(dep[u]=dep[si]+w[u])(深度也就等于编号) 移项得(dep[u]-w[u]=dep[si]),可以发现,对(u)产生贡献的点的位置确定。
    所以我们开一个(val[])数组,(val[i])表示路径的起点的深度为(i)的路径有多少条。再用两个(vector) (a),(b)记录一下以(i)为起点的路径,和以(i)为终点的路径的起点。
    那么在每个节点统计答案(ans[i]=val[dep[i]-w[i]])。(注意用(a),(b)修改(val)数组。)

    (3.)所有的(Si=1)

    若第(i)条路径对(u)点有贡献,那么需要保证(dep[u]=w[u])。然后(u)的子树中有几个路径的终点,(u)的答案就是几。
    (dfs)统计即可。

    (4.)所有的(Ti=1)

    若第(i)条路径对(u)点有贡献,那么有(dep[si]-dep[u]=w[u]),也就是(dep[u]+w[u]=dep[si])。用(val)数组记录一下深度为(i)的起点有多少个(就是(val[i])表示起点的深度为(i)的路径有多少条)。
    接下来对树进行(dfs),那么统计完子树的信息后(val[dep[u]+w[u]])增加的数值就是节点(u)的答案(因为不仅要保证深度满足条件,还要保证(si)(u)的子树内)。

    (5.)正解

    就是把以上几种情况的思想结合起来。
    首先,将一条从(u)(v)的路径拆成从(u)(lca)再从(lca)(v)。这样就分成了向上走和下走两种情况,分别计算。

    向上走的情况

    若第(i)条路径对(u)点有贡献,那么有(dep[si]-dep[u]=w[u]),也就是(dep[u]+w[u]=dep[si])
    借鉴部分分(Ti=1)时的思想,还是用(val)数组记录深度为(i)的起点有多少个。
    再借鉴(Si=1)的情况,开一个数组(nums[u])记录一下以(u)为起点的路径有多少条。
    因为终点变成了路径的(lca),不再是根节点,所以要考虑的一条(其实是半条)路径结束时的情况,借鉴部分分链时的情况,开一个(vector)(也可以用数组)记录一下以(u)(lca)的所有路径的起点。
    然后在(dfs)(u)点时,先(val[dep[u]]+=nums[u]),再将其对应的起点的深度的(val)减一,形象一点就是(:val)([)(u)(LCA)的路径的起点的深度(]--)。答案还是(val[dep[u]+w[u]])增加的数值。

    向下走的情况(首先声明(:leni)为第(i)条路径的长度)

    若第(i)条路径对(u)点有贡献,那么有(leni-(dep[ti]-dep[u])=w[u]),整理一下得到(dep[u]-w[u]=dep[ti]-leni)
    这次(val[X])表示的是满足(dep[ti]-leni=X)的路径有多少条。
    用两个(vector)分别在起点和终点记录一下该路径的(dep[t]-len)
    然后(dfs)统计答案,方法和上一个差不多。

    注意事项

    (1.)(dep[u]-w[u])可能会出现负值,不能作为数组的下标,所以要加上一个300000的偏移量。那么问题又来了,(val)数组要开大两倍。
    (2.)如果一条路径在(lca)处产生贡献,那么(lca)处要减掉一,因为在向上和向下两种情况中都产生了答案。
    (3.)还有最最重要的一条:(dfs)统计答案时一定要先加(以该点为起点的路径),然后统计答案,然后减(在该点结束的路径)。否则会漏掉(w[i]=0)的情况,并且终点处没有统计上答案。
    (4.)不要忘了(val)数组清零。

    圆满完成!
    上代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N = 300005;
    struct node{
    	int s,t,lca,len;
    }a[N];
    int head[N],tot;
    struct edge{
    	int node,next;
    }e[N<<1];
    int n,m,w[N],mdep;
    vector<int> upper[N],down1[N],down2[N];
    int f[N][30],dep[N],ans[N],nums[N],val[N<<1];//val[N]
    inline int read()
    {
    	char c=getchar();
    	int ans=0,w=1;
    	while((c<'0'||c>'9')&&c!='-') c=getchar();
    	if(c=='-') { w=-1; c=getchar(); }
    	while(c>='0'&&c<='9')
    	{ ans=ans*10+c-'0'; c=getchar(); }
    	return ans*w;
    }
    void add(int x,int y)
    {
    	e[++tot].node=y; 
    	e[tot].next=head[x];
    	head[x]=tot;
    }
    void dfs0(int u,int fa)
    {
    	f[u][0]=fa;
    	dep[u]=dep[fa]+1;
    	for(int i=head[u];i;i=e[i].next)
    	{
    		int v=e[i].node;
    		if(v==fa) continue;
    		dfs0(v,u);
    	}
    }
    void work()
    {
    	for(int i=1;i<=19;i++)
    	 for(int j=1;j<=n;j++)
    	  f[j][i]=f[f[j][i-1]][i-1];
    }
    int lca(int x,int y)
    {
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=19;i>=0;i--)
    	 if(dep[f[x][i]]>=dep[y])
    	  x=f[x][i];
    	if(x==y) return x;
    	for(int i=19;i>=0;i--)
    	if(f[x][i]!=f[y][i])
    	 x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    inline void dfs3(int u)
    {
    	int now=dep[u]+w[u],last=val[now];
    	for(int i=head[u];i;i=e[i].next)
    	 if(e[i].node!=f[u][0])
    	  dfs3(e[i].node);
    	val[dep[u]]+=nums[u];
    	ans[u]=val[now]-last;
    	for(int i=0;i<upper[u].size();i++)
    	 val[dep[upper[u][i]]]--;
    } 
    inline void dfs4(int u)
    {//cout<<"*";
    	int now=dep[u]-w[u]+300000,last=val[now];
    	for(int i=head[u];i;i=e[i].next)
    	 if(e[i].node!=f[u][0])
    	  dfs4(e[i].node);
    	for(int i=0;i<down1[u].size();i++)
    	 val[down1[u][i]+300000]++;
    	ans[u]+=val[now]-last;
    	for(int i=0;i<down2[u].size();i++)
    	 val[down2[u][i]+300000]--;
    }
    int main()
    {
    	n=read(); m=read();
    	int x,y;
    	for(int i=1;i<n;i++)
    	{
    		x=read(); y=read();
    		add(x,y); add(y,x);
    	}
    	for(int i=1;i<=n;i++)
    	 w[i]=read();
    	dfs0(1,0); work();//在前面  
    	for(int i=1;i<=m;i++)
    	{
    		a[i].s=read(); a[i].t=read();
    		a[i].lca=lca(a[i].s,a[i].t);
    		a[i].len=dep[a[i].s]+dep[a[i].t]-(dep[a[i].lca]<<1);
    		nums[a[i].s]++;// dep[a[i].lca<<1] 
    		upper[a[i].lca].push_back(a[i].s);
    	}
    	dfs3(1);
    	for(int i=1;i<=m;i++)
    	{
    		down1[a[i].t].push_back(dep[a[i].t]-a[i].len);
    		down2[a[i].lca].push_back(dep[a[i].t]-a[i].len);
    	}
    	memset(val,0,sizeof(val));
    	dfs4(1);
    	for(int i=1;i<=m;i++)
    	if(dep[a[i].s]==dep[a[i].lca]+w[a[i].lca])
    	 ans[a[i].lca]--;
    	for(int i=1;i<=n;i++)
    	 printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    [经验交流] kubernetes v1.11 更新了高可用方案
    Java泛型和编译优化的一个例子
    Java泛型和编译优化的一个例子
    Java泛型和编译优化的一个例子
    浅析JSONP-解决Ajax跨域访问问题
    java设计原则---开闭原则
    for,foreach,iterator的用法和区别
    List,Set,Map三种接口的区别
    为什么接口中定义的变量必须为常量?
    重写,string创建内存问题
  • 原文地址:https://www.cnblogs.com/karryW/p/10864646.html
Copyright © 2011-2022 走看看