hdu6393 Traffic Network in Numazu 树链剖分

题目传送门

题意:给出n个点n条边的无向带权图,再给出两种操作,操作1是将第x条边的边权修改为y,操作2是询问点x到点y的最短路径。

思路:如果是n个点n-1条边,题目就变成了树,修改边权和询问最短路径都可以在树链剖分上直接操作,而添加了一条边后,就在树上形成了一个环。

         读入的时候,用并查集判断哪条边是构成那个环的边(我们把这幅图想象成一棵树加上一条边),记录这条边。

    对于修改操作,对于树上的边,用树链剖分修改,对于特殊的边,直接修改。

    对于查询操作,只需要查询两个点在树上的路径,和两个点通过这条边的路径(这种方法有两个值)哪个最小就可以了。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int n,q,head[maxn],tot,u,v,fa[maxn],sc,me[maxn],size[maxn],l[maxn],r[maxn],fin[maxn],son[maxn];
int dep[maxn],top[maxn],hold[maxn];
ll sum[maxn<<2];
ll w,val[maxn];
struct edge{
    int u,v,id;
    ll w;
}a[maxn];
vector<edge >ve[maxn];
void init(){
    tot=0;
    for(int i=1;i<=n;i++){
        me[i]=i;
    }
    for(int i=1;i<=n;i++){
        ve[i].clear();
    }
}
int find(int x){
    return x==me[x]?x:me[x]=find(me[x]);
}
void build(int o,int ql,int qr){
    if(ql==qr){
        
        sum[o]=val[fin[ql]];
//        printf("ql:%d  qr:%d  sum[o]:%d  fin[ql]:%d\n",ql,qr,sum[o],fin[ql]);
        return;
    }
    int mid=(ql+qr)>>1;
    build(o<<1,ql,mid);
    build(o<<1|1,mid+1,qr);
    sum[o]=sum[o<<1]+sum[o<<1|1];
}
void update(int o,int ql,int qr,int p,int v){
    if(ql==qr){
        sum[o]=v;
        return;
    }
    int mid=(ql+qr)>>1;
    if(p<=mid)update(o<<1,ql,mid,p,v);
    else update(o<<1|1,mid+1,qr,p,v);
    sum[o]=sum[o<<1]+sum[o<<1|1];
}
ll query(int o,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return sum[o];
    int mid=(l+r)>>1;
    ll res=0;
    if(ql<=mid)res+=query(o<<1,l,mid,ql,qr);
    if(qr>mid)res+=query(o<<1|1,mid+1,r,ql,qr);
    return res;
}
inline ll get(int x)
{
    ll ret = 0;
    while(top[x]!=1)
    {
//        printf("top[x]:%d\n",top[x]);
        ret+=query(1,1,n,l[top[x]],l[x]);
        x=fa[top[x]];
    }
    ret+=query(1,1,n,1,l[x]);
    return ret;
}
int lca(int x,int y){
    while(top[x]!=top[y])
        {
            if(dep[top[x]]>=dep[top[y]])x=fa[top[x]];
            else y=fa[top[y]];
        }
    return dep[x]<dep[y]?x:y;
}
inline void dfs_1(int x,int pre)
{
//    printf("x:%d  pre:%d\n",x,pre);
    fa[x] = pre;
    son[x] = -1;
    size[x] = 1;
    dep[x] = dep[pre]+1;
    int si=ve[x].size();
    for(int i = 0; i < si; i++){
        int v=ve[x][i].v;
        
        if( v!= pre)
        {
            val[v]=ve[x][i].w;
            hold[ve[x][i].id]=v;
            dfs_1(v,x);
            size[x] += size[v];
            if(son[x]==-1 || size[v]>size[son[x]]) son[x] = v;
        }
    }
}
inline void dfs_2(int x,int root)
{
    top[x] = root;
    l[x]  = ++tot;
    fin[l[x]] = x;
    if(son[x] != -1)
    dfs_2(son[x],root);
    int si=ve[x].size();
    for(int i = 0; i < si; i++){
        int v=ve[x][i].v;
        if(v != fa[x] && v != son[x])
            dfs_2(v,v);
        }
    r[x]=tot;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        scanf("%d%d",&n,&q);
        init();
        for(int i=1;i<=n;i++){
            scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].w);
            a[i].id=i;
            int fu=find(a[i].u),fv=find(a[i].v);
//            printf("u:%d  v:%d  fu:%d  fv:%d\n",u,v,fu,fv);
            if(fu!=fv){
                me[fu]=fv;
                ve[a[i].u].push_back({a[i].u,a[i].v,i,a[i].w});
                ve[a[i].v].push_back({a[i].v,a[i].u,i,a[i].w});
            }else{
                sc=i;
            }
        }
        
        dfs_1(1,0);
//        printf("debug\n");
        dfs_2(1,1);
        build(1,1,n);
        int op,x,y;
        while(q--){
            scanf("%d%d%d",&op,&x,&y);
            if(op==0){
                if(x==sc){
                    a[sc].w=y;
                }else{
                    update(1,1,n,l[hold[x]],y);
                }
            }else{
                int lc=lca(x,y);
                ll ans=get(x)+get(y)-2*get(lc);
                ll res1=get(x)+get(a[sc].u)-2*(get(lca(x,a[sc].u)))+get(y)+get(a[sc].v)-2*(get(lca(y,a[sc].v)));
                ll res2=get(x)+get(a[sc].v)-2*(get(lca(x,a[sc].v)))+get(y)+get(a[sc].u)-2*(get(lca(y,a[sc].u)));
                printf("%lld\n",min(ans,a[sc].w+min(res1,res2)));
            }
        }
    }
} 

 

posted @ 2019-07-04 17:23  光芒万丈小太阳  阅读(180)  评论(0编辑  收藏  举报