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[x];
        }
        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\n",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;
}

猜你喜欢

转载自www.cnblogs.com/lhclqslove/p/9492860.html