P3066 [USACO12DEC] Running Away From the Barn G(树上倍增+差分)
原题:https://www.luogu.com.cn/problem/P3066
思路:对每个节点i,倍增找到能贡献的最远的点k,问题就相当于i点到k点路径上都+1,树上差分就行。如差分数组cf[i]++,cf[fa[k]]--。
#include<iostream> #include<algorithm> #include<fstream> #include<cstring> #include<cstdio> #include<sstream> #include<vector> #include<stack> #include<deque> #include<cmath> #include<map> #include<queue> #include<bitset> //#include<hash_map> #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define all(a) a.begin(),a.end() #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; //using namespace __gnu_cxx; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int maxn=2e5+79; //const int mod=1e9+7; const int INF=1e9+7; const double pi=acos(-1); struct od { int to,nxt; ll val; }e[maxn<<1]; ll n,m,Ev,p; ll dis[maxn]; ll f[maxn][32],d[maxn],head[maxn],cf[maxn]; void addEdge(int u,int v,ll c) { e[++Ev].to=v; e[Ev].nxt=head[u]; e[Ev].val=c; head[u]=Ev; } void dfs1(int u,int prev,int dep) { //这次dfs是预处理倍增和dis[i],点i到根的距离 f[u][0]=prev;d[u]=dep; fu(i,1,30) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];i!=-1;i=e[i].nxt) { int v=e[i].to; if(v==prev) continue; dis[v]=dis[u]+e[i].val; dfs1(v,u,dep+1); } } bool jud(int u,int ff) { return dis[u]-dis[ff]<=m; } ll find(int u,int fir) { //不断倍增找距离<=t的父节点 int k=u; fu(i,0,30) { int ff=f[u][i]; if(ff&&jud(fir,ff)) k=ff; else break; } return k; } void work(int u) { int k=u; while(k!=find(k,u)) k=find(k,u); cf[u]++,cf[f[k][0]]--; } void dfs2(int u,int prev) { //这次dfs是进行差分 work(u);//差分标记 for(int i=head[u];i!=-1;i=e[i].nxt) { int v=e[i].to; if(v==prev) continue; dfs2(v,u); } } void dfs0(int u,int fa) { //这次dfs是求差分后结果 for(int i=head[u];i!=-1;i=e[i].nxt) { int v=e[i].to; if(v==fa) continue; dfs0(v,u); cf[u]+=cf[v]; } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); ms(head,-1); cin>>n>>m; fu(i,2,n) { ll u,v;cin>>u>>v; addEdge(i,u,v);addEdge(u,i,v); } dfs1(1,0,1); dfs2(1,0); dfs0(1,0); fu(i,1,n) cout<<cf[i]<<endl; return 0; }