POJ 2763 Housewife Wind【LCA_RMQ+树状数组】

题意: 知道了一颗有  n 个节点的树和树上每条边的权值,对应两种操作:

          0 x        输出 当前节点到 x节点的最短距离,并移动到 x 节点位置

          1 x val   把第 x 条边的权值改为 val

分析: 树上两个节点a,b的距离可以转化为

          dis[a] + dis[b] - 2*dis[lca(a,b)]

          其中 dis[i] 表示 i 节点到根的距离,

          由于每次修改一条边,树中在这条边下方的 dis[] 值全都会受到影响,这样每条边都对应这一段这条边的管辖区,

          可以深搜保存遍历该点的时间戳,ll[i] 表示第一次遍历到该点的时间戳, rr[i] 表示回溯到该点时的时间戳,这样每次

          修改边 i 的时候就可以对区间 [ ll[i], rr[i] ] 进行成段更新,成段更新的方式可以在 位置 ll[i] 上加一个权值,在位置

          rr[i]+1 上减去这个权值,求和时,sum(ll[i]) 即为该点到根的距离。

#include<stdio.h>
#include<string.h>
#include<math.h>
#define clr(x)memset(x,0,sizeof(x))
#define maxn 200005
struct node
{
    int to,next,w,xu;
}e[1000000];
int tot;
int head[maxn];
void add(int s,int t,int wi,int xu)
{
    e[tot].xu=xu;
    e[tot].w=wi;
    e[tot].to=t;
    e[tot].next=head[s];
    head[s]=tot++;
}
int dp[maxn<<1][18];
int x[maxn<<1];
int d[maxn];
int r[maxn];
int v[maxn];
int f[maxn];
int ll[maxn];
int rr[maxn];
int g[maxn];
int n,m;
int min(int i,int j)
{
    return d[i]<d[j]?i:j;
}
void makermq(int nn)
{
    int i,j;
    for(i=0;i<nn;i++)
        dp[i][0]=i;
    for(j=1;(1<<j)<=nn;j++)
        for(i=1;i+(1<<j)-1<nn;i++)
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r)
{
    int k=(int)(log((r-l+1)*1.0)/log(2.0));
    return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int cnt,ti;
void dfs(int u,int deep)
{
    v[u]=1;
    x[cnt]=u;
    d[cnt]=deep;
    r[u]=cnt++;
    ll[u]=++ti;
    int i,k;
    for(i=head[u];i;i=e[i].next)
    {
        k=e[i].to;
        if(!v[k])
        {
            g[e[i].xu]=k;
            dfs(k,deep+1);
            x[cnt]=u;
            d[cnt++]=deep;
        }
    }
    rr[u]=ti;
}
int tree[maxn];
int lowbit(int x)
{
    return (x)&(-x);
}
void update(int pos,int x)
{
    while(pos<=n)
    {
        tree[pos]+=x;
        pos+=lowbit(pos);
    }
}
int sum(int pos)
{
    int s=0;
    while(pos>0)
    {
        s+=tree[pos];
        pos-=lowbit(pos);
    }
    return s;
}
int edge[maxn];
int val[maxn];
int main()
{
    int i,st;
    while(scanf("%d%d%d",&n,&m,&st)!=EOF)
    {
        int a,b,c;
        clr(head);  clr(v);
        clr(f);     clr(tree);
        tot=1;
        ti=-1;
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            val[i]=c;
            edge[i]=c;
            add(a,b,c,i);
            add(b,a,c,i);
        }
        cnt=0;
        dfs(1,0);
        makermq(2*n-1);
        for(i=1;i<n;i++)
        {
            update(ll[g[i]],edge[i]);
            update(rr[g[i]]+1,-edge[i]);
        }
        int op;
        while(m--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d",&a,&b);
                update(ll[g[a]],-val[a]);
                update(rr[g[a]]+1,val[a]);
                update(ll[g[a]],b);
                update(rr[g[a]]+1,-b);
                val[a]=b;
            }
            else
            {
                scanf("%d",&a);
                int lca,d1,d2,d3;
                if(r[st]<=r[a])
                     lca=x[rmq(r[st],r[a])];
                else lca=x[rmq(r[a],r[st])];
                d1=sum(ll[st]);
                d2=sum(ll[a]);
                d3=sum(ll[lca]);
                st=a;
                printf("%d\n",d1+d2-2*d3);
            }
        }
    }
    return 0;
}

 

posted @ 2012-10-03 10:22  'wind  阅读(1666)  评论(0编辑  收藏  举报