HDU 5044 Tree(LCA ,2014上海网络赛1003)

来源:互联网 发布:淘宝代付可以信用卡吗 编辑:程序博客网 时间:2024/04/27 22:20

题目:Tree

题意:又是一棵树,两种操作:

ADD1 U V K:将U到V结点路上的结点的权值都增加K;

ADD2 U V K:将U到V结点路上的边的权值都增加K;

最后输出所有点和所有边的权值。

我的做法是找到U, V的最近公共祖先X。

add[i][0]表示第i个点的权值。

des[i]表示第i个点在计算完之后,应该减少的权值。

add[i][1]表示第i个点跟其父结点之间的边的权值。

如果是操作1:

add[U][0] += K;add[V][0] += K;add[X][0] -= K;des[X] += K;

如果是操作2:

add[U][1] += K;add[V][1] += K;add[X][1] -= K*2;

这里作下解释:

因为我最后是从叶子结点出发往他们的父亲传递。

对于第一种操作,肯定U到X的路径的结点增加K,V到X的路径也增加K。

所以我们可以通过将add[U][0]和add[V][0]的信息不断传递上去,直到X为止。

由于U和V都会传递一个K给X,所以add[X][0]减掉一个K。

处理完X了,K不能再传给其父节点,所以再用des[X]减掉一次。

对于第二种操作,同理,也是不断将信息向上传递。但由于这里是边,不会算两次,所以直接在X的位置减掉两倍K即可。

传递的时候,可以搞个队列不断把叶子结点(deg为0)的添加进去,处理就行了。

最后注意下N=1的时候,虽然没有边,但是输出边权还是要留个空行给它。比赛因此吃了个久违的PE。。。

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>#include<vector>using namespace std;const int N = 100001;const int LOG = 20;#pragma comment(linker, "/STACK:102400000,102400000")#define pb push_backstruct Edge{    int to, id;    Edge(){}    Edge(int to, int id):to(to),id(id){}};;vector<Edge> V[N];typedef long long LL;LL add[N][2], des[N], node[N], edge[N];int n;int parent[LOG][N];int depth[N], top[N];int deg[N];void dfs(int x, int fa){parent[0][x] = fa;deg[x]=0;for(int i=0; i<V[x].size(); i++){        Edge &e = V[x][i];int j = e.to;if(j!=fa){            deg[x]++;            top[j] = e.id;depth[j] = depth[x]+1;dfs(j, x);}}}void init(){depth[1] = 0;dfs(1, -1);for(int k=0; k+1<LOG; k++){for(int v=1; v<=n; v++){if(parent[k][v]<0)parent[k+1][v]=-1;elseparent[k+1][v] = parent[k][parent[k][v]];}}}int lca(int u, int v){if(depth[u]>depth[v])swap(u, v);for(int k=0; k<LOG; k++){if((depth[v]-depth[u]) >> k&1){v = parent[k][v];}}if(u==v)return u;for(int k=LOG-1; k>=0; k--){if(parent[k][u]!=parent[k][v]){u = parent[k][u];v = parent[k][v];}}return parent[0][u];}void solve(){    queue<int> Q;    for(int i=1; i<=n; i++){        if(!deg[i])  Q.push(i);    }    while(!Q.empty()){        int x=Q.front(); Q.pop();        node[x] = add[x][0];        add[x][0] -= des[x];        int j = parent[0][x];        add[j][0] += add[x][0];        add[j][1] += add[x][1];        edge[top[x]] = add[x][1];        if(!(--deg[j]))    Q.push(j);    }}inline void in(int &x){    x = 0;    bool mk = 0;    char c=getchar();    while(c<48 || c>57){        if(c=='-')  mk=1;        c=getchar();    }    while(c>=48 &&c<=57){        x = x*10+c-48;        c = getchar();    }    if(mk)  x = -x;}int main(){    //freopen("C.txt", "r", stdin);    //freopen("C2.txt", "w", stdout);    int T, q;    in(T);    for(int t=1; t<=T; t++){        in(n); in(q);        for(int i=1; i<=n; i++){            V[i].clear();            add[i][0] = add[i][1] = 0;            des[i] = 0;        }        int a, b, c;        char op[10];        for(int i=1; i<n; i++){            in(a); in(b);            V[a].pb(Edge(b, i));            V[b].pb(Edge(a, i));        }        init();        while(q--){            scanf("%s", op);            in(a); in(b); in(c);            int x = lca(a, b);            if(op[3]=='1'){                add[a][0] += c;                add[b][0] += c;                add[x][0] -= c;                des[x] += c;            }            else{                add[a][1] += c;                add[b][1] += c;                add[x][1] -= c*2;            }        }        solve();        printf("Case #%d:\n", t);        for(int i=1; i<=n; i++){            printf("%I64d%c", node[i], i==n?'\n':' ');        }        for(int i=1; i<n; i++){            printf("%I64d%c", edge[i], i==n-1?'\n':' ');        }        if(n==1)    puts("");    }    return 0;}


0 0