• 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
    ",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
    ",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
    ",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
    ",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
    ");
            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
    ",min(ans,a[sc].w+min(res1,res2)));
                }
            }
        }
    } 
  • 相关阅读:
    C、C++笔记
    日向blog开发记录
    項目生成順序錯誤導致的鏈接ERROR
    vs单元测试demo
    让CtrlList的某一行自定义颜色
    MFC软件的一点没用的调试经验……
    VS单步调试DLL形式的COM组件的过程
    socket udp编程的一些积累的记录
    git push报错大文件,删除后重新commit依然报错
    CC++串口通信编程的一点技术记录
  • 原文地址:https://www.cnblogs.com/mountaink/p/11133716.html
Copyright © 2020-2023  润新知