天天爱跑步

题目传送门

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

先来看部分分

$1.$25分

(当然是大暴力了!)

\(2.\)一条链

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

若第\(i\)条路径对\(u\)点有贡献,当且仅当\(dep[u]=dep[si]+w[u]\)(深度也就等于编号) 移项得\(dep[u]-w[u]=dep[si]\),可以发现,对\(u\)产生贡献的点的位置确定。
所以我们开一个\(val[]\)数组,\(val[i]\)表示路径的起点的深度为\(i\)的路径有多少条。再用两个数组\(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;
}

猜你喜欢

转载自www.cnblogs.com/karryW/p/10864646.html