很显然的一个想法就是通过有食蚁兽的那一条边把整棵树分成两棵树.这样就可以两边乱搞了
对于一棵子树,我们现在存一下现在的上界r和下界l,遇到一个度为k的节点,分开之后它的上界和下界会变成 [l∗k,(r+1)∗k−1] .
然后遇到叶子节点的时候,我们在原序列中询问 [l,r] 之间的数有多少个就行了,只用把原序列排个序,二分一下就行了.
#include
#include
#include
#include
#include
#define M 1000005
#define LL long long
using namespace std;
void Rd(int &res){
res=0;char p;
while(p=getchar(),p<'0');
do{
res=(res<<1)+(res<<3)+(p^48);
}while(p=getchar(),p>='0');
}
struct W{
int to,nx;
}Lis[M<<1];
int Head[M],tot=0,degree[M];
void Add(int x,int y){
Lis[tot].to=y,Lis[tot].nx=Head[x],Head[x]=tot++;degree[y]++;
Lis[tot].to=x,Lis[tot].nx=Head[y],Head[y]=tot++;degree[x]++;
}
int n,g,k,Mx=0,st1,st2;
int val[M];
LL ans=0;
void dfs(int x,int f,LL l,LL r){
if(l>Mx)return;
if(degree[x]==0){
ans+=1LL*k*(upper_bound(val+1,val+g+1,r)-lower_bound(val+1,val+g+1,l));
return;
}
LL nl=l*degree[x],nr=(r+1)*degree[x]-1;
if(degree[x]==1)nl=l,nr=r;
for(int i=Head[x];~i;i=Lis[i].nx){
int to=Lis[i].to;
if(to==f)continue;
dfs(to,x,nl,nr);
}
}
int main(){
memset(Head,-1,sizeof(Head));
Rd(n),Rd(g),Rd(k);
for(int i=1;i<=g;i++){
Rd(val[i]);
if(val[i]>Mx)Mx=val[i];
}
sort(val+1,val+g+1);
Rd(st1),Rd(st2);degree[st1]++,degree[st2]++;
for(int i=2,x,y;ifor(int i=1;i<=n;i++)degree[i]--;
dfs(st1,-1,k,k),dfs(st2,-1,k,k);
cout<return 0;
}