POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

题意分析

给出n个点,m个询问,和当前位置pos。
先给出n-1条边,u->v以及边权w。
然后有m个询问,询问分2种:
一是讲第i条边的边权修改为w。
二是询问从当前位置走到点x经过的边权和(下次询问就是从这点开始)。

边权的树链剖分,其实和点权的差不多。对于一条边u-v,及其边权w,在建立线段树的时候,将深度大的点,当做其边权w,如dep[u]>dep[v],就令newid[u] = w。这样一来,将边权问题转化为点权问题,需要注意的,就是在查询的时候,对于lca的处理。

处理方法也很简单,首先判断:当深度大的网上爬,爬到一定程度的时候,是否两点已经重合,若是的话,直接返回值就好。 否则,就用查询[深度小的儿子]到[深度大的这段区间],并将结果累加到ans中。

代码总览

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll int
#define nmax 100820
using namespace std;
int fa[nmax],son[nmax],sz[nmax],newid[nmax],hashback[nmax],dep[nmax],top[nmax];
int num,tot,head[nmax];
struct edge{
    int to;
    int next;
}edg[nmax<<1];
struct tree{
    int l,r,val;
    int mid(){
        return (l+r)>>1;
    }
}tree[nmax<<2];
struct mess{
    int u,v,w;
}mes[nmax];
void add(int u, int v){
    edg[tot].to = v;
    edg[tot].next = head[u];
    head[u] = tot++;
}
void dfsFirst(int rt, int f,int d){
    dep[rt] = d;
    fa[rt] = f;
    sz[rt] = 1;
    for(int i = head[rt]; i!= -1; i = edg[i].next){
        int nxt = edg[i].to;
        if(nxt != f){
            dfsFirst(nxt,rt,d+1);
            sz[rt]+=sz[nxt];
            if(son[rt] == -1 || sz[nxt] > sz[son[rt]]){
                son[rt] = nxt;
            }
        }

    }
}
void dfsSecond(int rt, int tp){
    top[rt] = tp;
    newid[rt] = ++num;
    if(son[rt] == -1) return;
    dfsSecond(son[rt],tp);
    for(int i = head[rt];i != -1; i = edg[i].next){
        int nxt = edg[i].to;
        if(nxt != son[rt] && nxt != fa[rt])
            dfsSecond(nxt,nxt);
    }
}
void init(){
    memset(tree,0,sizeof tree);
    memset(head,-1,sizeof head);
    memset(son,-1,sizeof son);
    memset(edg,0,sizeof edg);
    tot = num = 0;
}
void PushUp(int rt){
    tree[rt].val = tree[rt<<1].val + tree[rt<<1|1].val;
}
void Build(int l, int r, int rt){
    tree[rt].l = l; tree[rt].r = r;
    if(l == r){
        return;
    }
    Build(l,tree[rt].mid(),rt<<1);
    Build(tree[rt].mid()+1,r,rt<<1|1);
    PushUp(rt);
}
void UpdatePoint(int val, int pos, int rt){
    if(tree[rt].l == tree[rt].r){
        tree[rt].val = val ;
        return;
    }
    if(pos <= tree[rt].mid()) UpdatePoint(val,pos,rt<<1);
    else UpdatePoint(val,pos,rt<<1|1);
    PushUp(rt);
}
int QuerySUM(int l,int r,int rt)
{;
    if(l>tree[rt].r || r<tree[rt].l) return 0;
    if(l <= tree[rt].l && tree[rt].r <= r) return tree[rt].val;
    return QuerySUM(l,r,rt<<1) + QuerySUM(l,r,rt<<1|1);
}
long long  Find_SUM(int x, int y){
    int tx = top[x],ty =top[y];
    long long ans  = 0;
    while(tx != ty){
        if(dep[tx] < dep[ty]){
            swap(x,y);
            swap(tx,ty);
        }
        ans += QuerySUM(newid[tx],newid[x],1);
        x = fa[tx]; tx = top[x];
    }
    if(x == y) return ans;
    if(dep[x] > dep[y]) swap(x,y);
    ans += QuerySUM(newid[son[x]],newid[y],1);
    return ans;
}

int n,m;
int main()
{
//    freopen("in.txt","r",stdin);
    int m,x,y,posnow;
    int op;
    while(scanf("%d %d %d",&n,&m,&posnow)!=EOF){
        init();
        for(int i =1;i<=n-1;++i){
            scanf("%d %d %d",&mes[i].u,&mes[i].v,&mes[i].w);
            add(mes[i].u,mes[i].v);
            add(mes[i].v,mes[i].u);
        }
        num = 0;
        dfsFirst(1,0,1);
        dfsSecond(1,1);
        Build(1,n,1);
        for(int i = 1;i<=n-1;++i){
            if(dep[mes[i].u] > dep[mes[i].v])// v is bigger;
                swap(mes[i].u,mes[i].v);
            UpdatePoint(mes[i].w,newid[mes[i].v],1);

        }
//        printf("MESSA ID    DATA   FA   SON   SIZE   DEEP   NEWID  TOP  SEGHASH\n");
//        for(int i = 1;i<=n;++i){
//            printf("DEBUG %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",i,data[i],fa[i],son[i],sz[i],dep[i],newid[i],top[i],seghash[i]);
//        }
//
//        printf("MESSA ID   val\n");
//        for(int i = 1;i<=n;++i){
//            printf("DEBUF %d   %d\n",i,QuerySUM(i,i,1));
//        }
        for(int i = 0;i<m;++i){
            scanf("%d",&op);
            if(op == 1){//change
                scanf("%d %d",&x,&y);
                x = newid[mes[x].v];
                UpdatePoint(y,x,1);
            }else {//ask
                scanf("%d",&x);
                printf("%lld\n",Find_SUM(posnow,x));
                posnow = x;
            }
        }
    }
    return 0;
}
posted @ 2017-08-13 20:41  pengwill  阅读(165)  评论(0编辑  收藏  举报