(POJ) Housewife Wind (LCA + BIT)

【题意】给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值

思路:

这个题我 用的是 LCA + BIT

题目的要求是求两点之间的最短距离,然后还可以修改 边 的长度,

修改的话,我们可以用树状数组来维护,,

我们先找 dfs 序,一个点的时间戳有两个, 然后时间戳包含的就是自己的下面节点。

我们在维护树状数组的时候,在 in 时间戳 加value, 在 out  时间戳, 减 value。

这样并不会影响到兄弟节点。

既然我们可以在树状数组中修改,那我们就可以一开始就把所有数据都放在树状数组里。

树状数组维护的就是该节点到根节点的距离。-·+

这个题目是要修改边, 所以我们找 dfs 序的时候,以边的序号为节点,看看这个边包含了几个边。

一条边有两个节点,所以我们选择边的下面节点来代表这个边。选择上面的点没有意义。

最后我们是要找两点之间的距离的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define rep(i,a,b)  for (int i = a; i < b; i++)
#define per(i,a,b)  for (int i = a; i > b; i--)
#define low(x) ((x) & (-x))
using namespace std;
const int N = 2e5+1000;
struct edge
{
    int v,id,next;
}g[N*2];

int n,q,s;
int c[N*2];
int f[N][20],dep[N],in[N],out[N],val[N];
int cnt,sign,tim;
int head[N],idn[N];

void Add_edge(int u, int v, int id){
        sign++;
        g[sign].next = head[u];
        head[u] =sign;
        g[sign].v = v;
        g[sign].id = id;
        return;
}
void ADD(int x, int y){
        while(x <= tim){
                c[x] += y;
                x += (x & (-x));
        }
        return;
}
int sum(int x){
    int ans = 0;
    while(x > 0){
        ans += c[x];
        x -= (x & (-x));
    }
    return ans;
}
int lca(int x, int y){
        if (dep[x] < dep[y]) swap(x,y);
        for (int i = 19; i >= 0; i--)
        if (dep[f[x][i]] >= dep[y]) x = f[x][i];
        if (x == y)return x;
        for (int i = 19; i >= 0; i--)
        if (f[x][i] != f[y][i]){
                x = f[x][i]; y = f[y][i]; //注意这个地方是父亲节点的比较,不是深度。
        }
        return f[x][0];
}
void dfs(int u, int fa, int deep){
        f[u][0] = fa;
        dep[u] = deep;
        rep(i,1,20)
        f[u][i] = f[f[u][i-1]][i-1];
        for (int i = head[u]; i != -1; i = g[i].next){
                edge &e = g[i];
                if (e.v == fa) continue;
                in[e.id] = idn[e.v] = ++tim;
                dfs(e.v, u, deep+1);
                out[e.id] = ++tim;
        }
        return;
}

int main(){
    scanf("%d%d%d",&n,&q,&s);
    mem(head,-1);  sign = -1;
    rep(i,1,n){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        Add_edge(x,y,i);
        Add_edge(y,x,i);
        val[i] = z;
    }
    tim = 0;
    dfs(1,0,0);
    mem(c,0);
    for (int i = 1; i < n; i++){
        ADD(in[i],val[i]);
        ADD(out[i],-val[i]);
    }
        rep(i,0,q){
            int x,y,z;
            scanf("%d",&z);
            if (z == 0) {
                scanf("%d",&y);
                int ans = sum(idn[s]) + sum(idn[y]) - 2*sum(idn[lca(s,y)]);
                printf("%d\n",ans);
                s = y;
            } else{
                scanf("%d%d",&x,&y);
                int tot = y - val[x];
                ADD(in[x],tot);
                ADD(out[x],-tot);
                val[x] = y;
         
           }   
}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81537547
今日推荐