用树状数组维护f前缀和,复杂度O(nlog^2n),冲榜第一
为什么大家都用的容斥、可并堆、平衡树...
#include<iostream> #include<cstring> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=200005; const int INF=1<<29; int n,m; struct Edge{ int next,to,w; }e[MAXN<<1]; int ecnt,head[MAXN]; inline void add(int x,int y,int w){ e[++ecnt].next = head[x]; e[ecnt].to = y; e[ecnt].w = w; head[x] = ecnt; } int t[MAXN]; void update(int x,int val){ for(int i=x;i<=m;i+=i&-i)t[i]+=val; } int query(int x){ if(x==0) return 0; int ret=0; for(int i=x;i;i-=i&-i)ret+=t[i]; return ret; } bool vis[MAXN]; int siz[MAXN]; void getsiz(int x,int pre){ siz[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; getsiz(v,x); siz[x]+=siz[v]; } } int mn=INF,root; void getroot(int x,int pre,int tot){ int mx=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; mx=max(mx,siz[v]); getroot(v,x,tot); } mx=max(mx,tot-siz[x]); if(mx<mn) mn=mx,root=x; } int s[MAXN],sav[MAXN]; void dfs(int x,int pre,int dis){ if(dis>m) return; s[++s[0]]=dis;sav[++sav[0]]=dis; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; dfs(v,x,dis+e[i].w); } } int ans; void dac(int x){//Divide and Conquer :) sav[0]=0;mn=n; getsiz(x,-1); getroot(x,-1,siz[x]); int u=root;vis[u]=1; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(vis[v]) continue; s[0]=0;dfs(v,u,e[i].w); for(int j=s[0];j>=1;j--){ if(s[j]>m) continue; ans+=query(m-s[j]); } for(int j=s[0];j>=1;j--){ if(s[j]>m) continue; update(s[j],1); ans++; } } for(int i=sav[0];i>=1;i--){ if(sav[i]>m) continue; update(sav[i],-1); } for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(vis[v]) continue; dac(v); } } int main(){ n=rd(); int x,y,w; for(int i=1;i<n;i++){ x=rd();y=rd();w=rd(); add(x,y,w);add(y,x,w); } m=rd(); dac(1); cout<<ans; return 0; }