给定一颗n个结点的无根树,树上的每个点有一个非负整数点权,定义一条路径的价值为路径上的点权和-路径的点权最大值。
给定参数p,我们想知道,有多少不同的树上简单路径,满足它的价值恰好是p的倍数。
注意:单点算作一个路径;u ≠ v时,(u,v)和(v,u)只算一次。
本来是一道很裸的点剖题,但是很久没有打点剖了,并没有去打。
点剖的时候,每个点维护两个值,一个是最大值,还有一个是和。
然后以最大值为第一关键字排序(因为要使得这个最大值一定最大才好统计方案),然后用一个桶记录一下就好了。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=1e5+7,mxx=1e7+7;
int i,j,k,l,t,n,m,ans,p;
int first[maxn*2],last[maxn*2],next[maxn*2],num;
int a[maxn],z,dian,tot,c[mxx][2],tot1,size[maxn],g[maxn],tim;
bool bz[maxn];
struct node{
int da,sum;
}b[maxn],d[maxn];
bool cmp(node x,node y){return x.da<y.da;}
void add(int x,int y){last[++num]=y,next[num]=first[x],first[x]=num;}
void dfs1(int x,int y){
int i;
size[x]=1;
rep(i,x)if(!bz[last[i]]&&last[i]!=y)dfs1(last[i],x),size[x]+=size[last[i]];
}
void dfs2(int x,int y){
int i;bool az=1;
rep(i,x)if(!bz[last[i]]&&last[i]!=y){
if(size[last[i]]>dian/2)az=0;
dfs2(last[i],x);
}
if(az&&dian-size[x]<=dian/2)z=x;
}
void dfs3(int x,int y,int da,int sum){
int i;
b[++tot]=(node){da,sum};
rep(i,x)if(last[i]!=y&&!bz[last[i]])dfs3(last[i],x,max(da,g[last[i]]),(sum+a[last[i]])%p);
}
void fen(int x){
int i;
dfs1(x,0);dian=size[x];dfs2(x,0);x=z;
tot1=0;
bz[x]=1;
d[tot=1]=(node){g[x],a[x]};
rep(i,x){
if(bz[last[i]])continue;
tot=0;
dfs3(last[i],x,max(g[last[i]],g[x]),(a[x]+a[last[i]])%p);
fo(j,1,tot)d[++tot1]=b[j];
sort(b+1,b+1+tot,cmp);
++tim;
fo(j,1,tot){
k=((b[j].sum-b[j].da)%p+p)%p;
if(k)k=p-k;
if(c[k][0]!=tim)c[k][0]=tim,c[k][1]=0;
ans-=c[k][1];
k=((b[j].sum-a[x])%p+p)%p;
if(c[k][0]!=tim)c[k][0]=tim,c[k][1]=0;
c[k][1]++;
}
}
sort(d+1,d+1+tot1,cmp);
++tim;
fo(i,1,tot1){
k=((d[i].sum-d[i].da)%p+p)%p;
if(!k)ans++;else k=p-k;
if(c[k][0]!=tim)c[k][0]=tim,c[k][1]=0;
ans+=c[k][1];
k=((d[i].sum-a[x])%p+p)%p;
if(c[k][0]!=tim)c[k][0]=tim,c[k][1]=0;
c[k][1]++;
}
rep(i,x){
if(!bz[last[i]])fen(last[i]);
}
}
int main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d%d",&n,&p);
fo(i,1,n-1){
scanf("%d%d",&k,&l);
add(k,l),add(l,k);
}
fo(i,1,n)scanf("%d",&a[i]),g[i]=a[i],a[i]%=p;
fen(1);
printf("%d\n",ans+n);
}