CF.739B 【Alyona and a tree】(倍增+树上差分/二分树上差分)

题目链接:https://codeforces.com/contest/739/problem/B

题意:一棵根节点为1的树,每个点都有点值a[i],每条边也有权值,dist(v, u)表示从v到u边权和,当u时v的子孙并且dist(v, u)<=a[u]时u就受v控制,输出每个结点能控制的结点数。

解法1:倍增+树上差分

一开始不知道该怎么去写这个树上差分,后来看了别人的题解报告算是明白了。一开始就是简单的倍增,同时求出每个点x到1的距离,即d[x]=dis(1,x)。完成第一步dfs之后,就是把当前点x不断向上跳,比如跳到y了,dis(x,y)=d[x]-d[y]刚好<a[x],那么也就是说x~y里面所有的点(除去x)都可以控制x,那么就把y的父亲差分数组-1,x的父亲差分数组+1即可。

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=2e5+5;
int tot,head[maxn];
struct E{
    int to,next,w;
}edge[maxn<<1];
void add(int u,int v,int w){
    edge[tot].to=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,a[maxn];
int fa[maxn][40],vis[maxn],depth[maxn],d[maxn];
void dfs(int x,int step){
    depth[x]=step;vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(vis[v]) continue;
        fa[v][0]=x;
        d[v]=d[x]+edge[i].w;
        dfs(v,step+1);
    }
}
void bz(){
    for(int j=1;j<=30;j++){
        for(int i=1;i<=n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}
int C[maxn];
void solve(int x,int f){
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(v==f) continue;
        solve(v,x);
        C[x]+=C[v];
    }
}
int main(){
    scanf("%d",&n);mem(head,-1);
    rep(i,1,n) scanf("%d",&a[i]);
    rep(i,2,n){
        int p,w;scanf("%d%d",&p,&w);
        add(i,p,w);add(p,i,w);
    }    
    dfs(1,1);
    bz();
    for(int i=1;i<=n;i++){
        int now=i,dis=a[i];
        for(int j=19;j>=0;j--){
            if(d[now]-d[fa[now][j]]<=dis){
                dis+=(d[fa[now][j]]-d[now]);
                now=fa[now][j];
            }
        }
        C[fa[i][0]]++;C[fa[now][0]]--;
    }
    solve(1,0);
    rep(i,1,n){
        printf("%d ",C[i]);
    }
    puts("");
}
View Code

 

posted @ 2020-08-30 13:52  Anonytt  阅读(188)  评论(0编辑  收藏  举报