zoukankan      html  css  js  c++  java
  • HDU 6392 Traffic Network in Numazu, 并查集+树链抛分

    HDU 6392 Traffic Network in Numazu,

    题目连接: Traffic Network in Numazu,

    题意:给你一颗基环树,让你支持两种操作,第一种询问从x到y的最短路径和,第二种修改某一条边的边权。

    题解:如果只是树上的话,就是裸的树链抛分。现在多了一条边,有环就不好做了,我们可以去掉环上的一条边然后就是一棵树了,然后怎么去边就是用并查集维护就可以了,每次来一条边就连接这个两个并查集,如果这两个并查集已经在一起了就说明这条边在环上。

    #include<bits/stdc++.h>
    #define ll long long
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define eps 1e-10;
    using namespace std;
    const int N = 1e5+7;
    int n,m;
    int head[N],cnt,to[N*2],nxt[N*2],w[N*2],id[N*2],te;//存边
    struct edge
    {
        int u,v,w;
    }e[N];
    bool vis[N];
    void add_edge(int u,int v,int len,int idx)
    {
        to[++cnt]=v;w[cnt]=len;id[cnt]=idx;nxt[cnt]=head[u];head[u]=cnt;
    }
    //并查级找环上的边
    int pre[N];
    int find(int x)
    {
        return pre[x]==x?x:pre[x]=find(pre[x]);
    }
    int dep[N],fa[N],top[N],tid[N],son[N],siz[N],cn,num[N];
    //树链抛分部分
    void dfs1(int u,int f,int d,int len)//第一次dfs用来找重儿子,深度,子树大小,父亲,以及把边权付给更深的那一点
    {
        fa[u]=f;dep[u]=d;siz[u]=1;num[u]=len;
        for(int i=head[u];i;i=nxt[i])
        {
            if(id[i]==te)continue;
            if(to[i]!=f)
            {
                dfs1(to[i],u,d+1,w[i]);siz[u]+=siz[to[i]];
                if(son[u]==-1||siz[to[i]]>siz[son[u]])son[u]=to[i];
            }
        }
    }
    void dfs2(int v,int tp)//得到重链的头节点,以及时间戳
    {
        top[v]=tp;
        tid[v]=++cn;
        if(son[v]==-1)return;
        dfs2(son[v],tp);
        for(int i=head[v];i;i=nxt[i])
        {
            if(id[i]==te)continue;
            if(to[i]!=fa[v]&&to[i]!=son[v])
            {
                dfs2(to[i],to[i]);
            }
        }
    }
    //线段树部分
    ll sum[N<<2],val[N];//线段树维护和
    void push_up(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void built(int l,int r,int rt)//建树
    {
        if(l==r)
        {
            sum[rt]=val[l];
            return ;
        }
        int m=(l+r)>>1;
        built(ls);
        built(rs);
        push_up(rt);
    }
    void update(int p,int va,int l,int r,int rt)//单点更新
    {
        if(l==r)
        {
            sum[rt]=va;return;
        }
        int m=(l+r)>>1;
        if(p<=m)update(p,va,ls);
        else update(p,va,rs);
        push_up(rt);
    }
    ll query(int L,int R,int l,int r,int rt)//询问和
    {
        if(L<=l&&r<=R)
        {
            return sum[rt];
        }
        int m=l+r>>1;ll ans=0;
        if(L<=m)ans+=query(L,R,ls);
        if(R>m)ans+=query(L,R,rs);
        return ans;
    }
    ll slove(int x,int y)//求x到y的最短距离
    {
        ll ans=0;
        int fx=top[x],fy=top[y];
        while(top[fx]!=top[fy])
        {
            if(dep[fx]>dep[fy])
            {
                ans+=query(tid[fx],tid[x],1,n,1);x=fa[fx];
            }
            else
            {
                ans+=query(tid[fy],tid[y],1,n,1);y=fa[fy];
            }
            fx=top[x];fy=top[y];
        }
            if(x!=y)
            {
                if(dep[x]>dep[y])swap(x,y);
                ans+=query(tid[son[x]],tid[y],1,n,1);//注意细节不要加lca的权值
            }
            return ans;
    }
    void init()
    {
        cn=cnt=0;te=0;
        memset(head,0,sizeof(head));
        memset(son,-1,sizeof(son));
        for(int i=0;i<=n;i++)pre[i]=i;
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--)
        {
           scanf("%d %d",&n,&m);
            init();
           for(int i=1;i<=n;i++)
           {
                int u,v,w;
                scanf("%d %d %d",&u,&v,&w);
                e[i].u=u;e[i].v=v;e[i].w=w;
                if(te==0)
                {
                     int fu=find(u),fv=find(v);
                     if(fu==fv)
                     {
                        te=i;
                     }
                     else pre[fu]=fv;
                }
                add_edge(u,v,w,i);
                add_edge(v,u,w,i);
           }
            dfs1(1,0,0,0);
            dfs2(1,1);
            num[1]=0;
            for(int i=1;i<=n;i++)val[tid[i]]=num[i];
            built(1,n,1);
            while(m--)
            {
                int op,x,y;
                scanf("%d %d %d",&op,&x,&y);
                if(op)
                {
                    ll ans=slove(x,y);
                    ans=min(ans,e[te].w+slove(x,e[te].u)+slove(y,e[te].v));
                    ans=min(ans,e[te].w+slove(y,e[te].u)+slove(x,e[te].v));
                    printf("%lld
    ",ans);
                }
                else
                {
                    if(x==te)e[x].w=y;
                    else
                    {
                        if(dep[e[x].u]>dep[e[x].v])update(tid[e[x].u],y,1,n,1);
                        else update(tid[e[x].v],y,1,n,1);
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    linux uniq 命令实用手册
    linux sort 命令实用手册
    linux awk 命令实用手册
    如何高效使用vim
    15个有趣好玩的linux shell 命令
    一篇文章带你编写10种语言HelloWorld
    如何用hugo 搭建博客
    c++中的exit()
    枚举数据类型C++
    常见的字符测试函数
  • 原文地址:https://www.cnblogs.com/lhclqslove/p/9492860.html
Copyright © 2011-2022 走看看