题目链接:Codeforces - Close Vertices
以前写点分治的时候,都是直接计算而不是用容斥统计。碰到这道题就有点麻烦了,需要树套树统计。。。。
只有路径长度的容斥:
sort(sth+1,sth+Cnt+1);
while(l<r){
if(sth[l]+sth[r]<=k){
ret+=r-l;
l++;
}else{
r--;
}
}
return ret;
所以就写的容斥计算的。其实是统计一个二维偏序。
所以我们用fenwick即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,sl,sw,mx,sum,rt,sz[N],vis[N],cnt,d[N],res;
int head[N],nex[N<<1],to[N<<1],w[N<<1],tot;
struct node{int d,w;}t[N];
int cmp(node a,node b){return a.w<b.w;}
inline void ade(int a,int b,int c){
to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c){ade(a,b,c); ade(b,a,c);}
inline void insert(int x,int v){for(;x<=n+1;x+=x&(-x)) d[x]+=v;}
inline int ask(int x){int s=0; for(;x;x-=x&(-x)) s+=d[x]; return s;}
void get(int x,int fa){
sz[x]=1; int t=0;
for(int i=head[x];i;i=nex[i]){
if(vis[to[i]]||to[i]==fa) continue;
get(to[i],x); sz[x]+=sz[to[i]]; t=max(t,sz[to[i]]);
}
t=max(t,sum-sz[x]); if(t<mx) mx=t,rt=x;
}
void getdis(int x,int fa,int d1,int w1){
t[++cnt]={d1,w1};
for(int i=head[x];i;i=nex[i]){
if(vis[to[i]]||to[i]==fa) continue;
getdis(to[i],x,d1+1,w1+w[i]);
}
}
int calc(int x,int d1,int w1){
cnt=0; getdis(x,0,d1,w1); int res=0;
sort(t+1,t+1+cnt,cmp);
int l=1,r=cnt;
for(int i=1;i<=cnt;i++) insert(t[i].d+1,1);
while(l<r){
if(t[l].w+t[r].w<=sw){
insert(t[l].d+1,-1);
if(sl-t[l].d+1>0) res+=ask(sl-t[l].d+1);
l++;
}else insert(t[r].d+1,-1),r--;
}
insert(t[l].d+1,-1);
return res;
}
void divide(int x){
vis[x]=1; res+=calc(x,0,0);
for(int i=head[x];i;i=nex[i]){
if(vis[to[i]]) continue; res-=calc(to[i],1,w[i]);
mx=sum=sz[to[i]]; get(to[i],x); get(rt,x);
divide(rt);
}
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr);
cin>>n>>sl>>sw;
for(int i=2,a,b;i<=n;i++) cin>>a>>b,add(i,a,b);
mx=sum=n; get(1,0); get(rt,0); divide(rt);
cout<<res;
return 0;
}