poj 2763 Housewife Wind (LCA转RMQ+树状数组)

题意:给一棵树,两种操作:

1、求两点间路径长度

2、修改某条路径长度。


对于操作1,先求两点的LCA,设d[i]为结点i到根结点的距离,那么两点路径长度就等于d[u]+d[c]-2*d[lca(u,v)],求LCA可转化为RMQ来求。

对于操作2,考虑修改之后对操作1的影响,即修改之后,会使得以该边的某一个端点为根的子树中所有结点的d发生变化。

用L[u],R[u]分别表示结点u的dfs序、回溯到u时的dfs序,那么修改某一条边的时候,设该边dfs序较大的那个端点为u,则d受影响的顶点就是dfs序位于区间[L[u],R[u]]的所有顶点。因此可以考虑用树状数组(或者线段树之类的)来维护区间的值。对于每一个顶点的dfs序给予一个权值,初始化为0。每个顶点u其到根结点的距离为区间[0,L[u]]的和

对于每一条边i,设其dfs序较大的那个端点为G[i],每次更新的时候,将L[G[i]]的权值加上一个w(更新的值),R[G[i]]+1的权值减去一个w,这样,L[G[i]]~R[G[i]区间内的所有顶点在求和的时候和(即该结点到根的距离)都增加了w,而区间外的结点不受影响。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
#define maxn 100001
struct Edge{
    int to,next,w;
}edge[maxn<<1];

int n,a[maxn],head[maxn],dep[maxn<<1],cnt,pos[maxn],E[maxn<<1],dfn,f[maxn<<1][20];
int W[maxn],L[maxn],R[maxn],dfs_clock,C[maxn],G[maxn];

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

inline int lowbit(int x){return (x)&(-x);}

void init()
{
    memset(head,-1,sizeof(head));
    memset(pos,-1,sizeof(pos));
    memset(C,0,sizeof(C));
    cnt=dfn=0;
    dfs_clock=0;
}

void dfs(int u,int deep)
{
    E[dfn]=u,dep[dfn]=deep,pos[u]=dfn++;
    L[u]=++dfs_clock;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(pos[v]==-1)
        {
            G[edge[i].w]=v;
            dfs(v,deep+1);
            E[dfn]=u,dep[dfn++]=deep;
        }
    }
    R[u]=dfs_clock;
}

void init_RMQ(int n)
{
    for(int i=1;i<=n;++i) f[i][0]=i;
    for(int j=1;(1<<j)<=n;++j)
        for(int i=1;i+(1<<j)-1<=n;++i)
        {
            if(dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]) f[i][j]=f[i][j-1];
            else f[i][j]=f[i+(1<<(j-1))][j-1];
        }
}

inline int RMQ(int L,int R)
{
    int k=0;
    while(1<<(k+1)<=R-L+1) ++k;
    if(dep[f[L][k]]<dep[f[R-(1<<k)+1][k]]) return f[L][k];
    return f[R-(1<<k)+1][k];
}

inline int lca(int u,int v)
{
    if(pos[u]>pos[v]) return E[RMQ(pos[v],pos[u])];
    return E[RMQ(pos[u],pos[v])];
}

inline void update(int i,int x)
{
    for(;i<=n;i+=lowbit(i)) C[i]+=x;
}

inline int sum(int i)
{
    int s=0;
    for(;i>0;i-=lowbit(i)) s+=C[i];
    return s;
}

int main()
{
    int i,u,v,k,q,w,s;
    while(~scanf("%d%d%d",&n,&q,&s))
    {
        init();
        for(i=1;i<n;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,i);
            add(v,u,i);
            W[i]=w;
        }
        dfs(1,0);
        init_RMQ(2*n-1);
        u=s;
        for(i=1;i<n;++i)
        {
            update(L[G[i]],W[i]);
            update(R[G[i]]+1,-W[i]);
        }
        while(q--)
        {
            scanf("%d",&k);
            if(k){
                scanf("%d%d",&u,&w);
                update(L[G[u]],w-W[u]);
                update(R[G[u]]+1,-w+W[u]);
                W[u]=w;
            }
            else{
                scanf("%d",&v);
                printf("%d\n",sum(L[s])+sum(L[v])-2*sum(L[lca(s,v)]));
                s=v;
            }
        }
    }
    return 0;
}


你可能感兴趣的:(poj 2763 Housewife Wind (LCA转RMQ+树状数组))