[JLOI2014]松鼠的新家 (luogu P3258) 树上差分

https://www.luogu.org/problemnew/show/P3258

(树剖裸题


树上差分 = = 差分 + lca

1. 树上差分基本思想:和差分一样,用前缀和的思想来处理解(操作后的树上,任意节点的糖果数 是通过所有与其相连的子节点的和 以及该节点在差分数组里的值 得到的(dfs);

2. 因为这道题并不需要除了lca以外的信息,故tarjan

对于一组修改u,v :只需修改差分数组 ----- diff[u]++, diff[v], diff[lca(u,v)]--, diff[fa[lca(u,v)]]--

至于为什么,看1;

剩下自己想;;

// 15owzLy1
//luogu3258.cpp
//2018 09 25      18:45:43
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
typedef double db;
using namespace std;

const int N = 300005;
struct node {
    int next, to;
}edge[N<<1];
int set_[N], candy[N], diff[N], n, head[N], head_q[N], fa[N];
int query[N][2], a, b, c, cnt;
bool vis[N];

template<typename T>inline void read(T &x_) {
    x_=0;bool f_=0;char c_=getchar();
    while(c_<'0'||c_>'9'){f_|=(c_=='-');c_=getchar();}
    while(c_>='0'&&c_<='9'){x_=(x_<<1)+(x_<<3)+(c_^48);c_=getchar();}
    x_=f_?-x_:x_;
}

inline void jb(int u, int v) {
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
}

int get_set_(int x) {
    return (set_[x]==x)?x:set_[x]=get_set_(set_[x]);
}

inline void Merge(int x, int y) {
    set_[get_set_(y)]=get_set_(x);
}

void dfs(int u) {
    vis[u]=true;
    for(int i=head[u];i;i=edge[i].next) {
        int v=edge[i].to;
        if(v==fa[u]) continue;
        fa[v]=u;
        dfs(v);
        Merge(u, v);
    }

    if(vis[query[u][0]]) {
        a=get_set_(query[u][0]); 
        if(a!=get_set_(u)) {
            diff[a]--, diff[fa[a]]--;
            diff[u]++, diff[query[u][0]]++;
        }
    }
    if(vis[query[u][1]]) {
        a=get_set_(query[u][1]);
        if(a!=get_set_(u)) {
            diff[a]--, diff[fa[a]]--;
            diff[query[u][1]]++, diff[u]++;
        }
    }
}

void get_ans(int u) {
    candy[u]=diff[u];
    for(int i=head[u];i;i=edge[i].next) {
        int v=edge[i].to;
        if(v==fa[u]) continue;
        get_ans(v);
        candy[u]+=candy[v];
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("luogu3258.in","r",stdin);
    freopen("luogu3258.out","w",stdout);
#endif
    int x, y, a1;
    read(n); read(x); a1=x;
    for(int i=1;i<n;i++) {
        read(y);
        query[y][0]=x, query[x][1]=y;
        x=y;
    }

    for(int i=1;i<n;i++) read(x), read(y), jb(x, y), jb(y, x);
    for(int i=1;i<=n;i++) set_[i]=i;
    dfs(1); get_ans(1); candy[a1]++;
    for(int i=1;i<=n;i++)
        printf("%d\n", candy[i]-1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/15owzLy1-yiylcy/p/9727106.html