• luogu P4949 最短距离


    题目描述

    给出一个 N 个点 N 条边的无向连通图。

    你需要支持两种操作:

    1. 修改 第 x 条边的长度为 y ;

    2. 查询 点 x 到点 y 的最短距离。

    共有 {M}M 次操作。

    输入输出格式

    输入格式:

    输入共 N + M + 1 行:

    第 1 行,包含 2 个正整数 N,M,表示点数即边数,操作次数。

    第 2 行到第 N + 1 行,每行包含 3 个正整数 x,y,z,表示 x 与 y 间有一条长度 为 z 的边。

    第 N + 2 到 N + M + 1 行,每行包含 3 个正整数 opt,x,y,表示操作种类,操作的参数(含义见【题目描述】)。

    输出格式:

    对于每次操作 2 输出查询的结果。

    此题是一道基环树上树链剖分题目

    思路是这样的:基环树其实可以看做一棵树多连了一条边,于是我们可以通过加边时维护一个并查集,来找出多的那条边。

    将那条多出的边记录下来。

    然后我们考虑u到v的最大值,有两种情况

      u直接在树上到v

      u,v到多出的那条边的两端,通过这条边连在一起

    与是我们就可以很愉快的在树上跑树链剖分了,注意此题是边权而不是点权

    那我们对于u到v权值为w的一条边可以看做u->xx->v,u,v点权为0,xx点权为w,就可将边权转化为点权了,点数翻倍,记得数组大小翻倍哟

    值得一提的是我一开始线段树的数组忘记开4倍了,结果又WA又TLE40分,搞得我还以为哪里写错了呢

    实现如下:

    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #define lson l,mid,o<<1
    #define rson mid+1,r,o<<1|1
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int a=0,p=0;char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if(ch=='-') p=1,ch=getchar();
        while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+ch-'0',ch=getchar();
        return p?-a:a;
    }
    const int N=200100;
    int n,q,op,u,v,w,cnt,sum[N<<2],head[N],top[N],fe[N],fa[N],id[N],dep[N],size[N],son[N],ww[N],wn[N],tim=0,t1,t2,keu,kev,kew,kex,xu;
    int getf(int u){return fe[u]==u?u:fe[u]=getf(fe[u]);}
    struct EDGE{int nxt,to;}e[N<<1];
    void add(int u,int v){e[++cnt]=(EDGE){head[u],v};head[u]=cnt;}
    void build(int l,int r,int o)
    {
        if(l==r){sum[o]=wn[l];return;}
        int mid=(l+r)>>1;
        build(lson);build(rson);
        sum[o]=sum[o<<1]+sum[o<<1|1];
    }
    void update(int pre,int val,int l,int r,int o)
    {
        if(l==r){sum[o]=val;return;}
        int mid=(l+r)>>1;
        if(pre<=mid) update(pre,val,lson);
        else update(pre,val,rson);
        sum[o]=sum[o<<1]+sum[o<<1|1];
    }
    int query(int L,int R,int l,int r,int o)
    {
        if(L<=l&&r<=R) return sum[o];
        int mid=(l+r)>>1,ans=0;
        if(L<=mid) ans+=query(L,R,lson);
        if(R> mid) ans+=query(L,R,rson);
        return ans;
    }
    int query_tree(int u,int v)
    {
        int ans=0;
        while(top[u]!=top[v])
        {
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            ans+=query(id[top[u]],id[u],1,n,1);
            u=fa[top[u]];
        }
        if(dep[u]>dep[v]) swap(u,v);
        return ans+query(id[u],id[v],1,n,1);
    }
    void dfs1(int u,int ff)
    {
        fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1;
        int maxson=0;
        for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=ff)
        {
            dfs1(v,u);
            size[u]+=size[v];
            if(size[v]>maxson) maxson=size[v],son[u]=v;
        }
    }
    void dfs2(int u,int topf)
    {
        id[u]=++tim;top[u]=topf;wn[tim]=ww[u];
        if(!son[u]) return;
        dfs2(son[u],topf);
        for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=fa[u]&&v!=son[u])
            dfs2(v,v);
    }
    int main()
    {
    //    freopen("input","r",stdin);
    //    freopen("output","w",stdout);
        xu=n=read(),q=read();
        for(int i=1;i<=n;i++) fe[i]=i;
        for(int i=1;i<=n;i++)
        {
            u=read(),v=read(),w=read();
            t1=getf(u),t2=getf(v);
            if(t1!=t2)
            {
                fe[t1]=t2;xu=n+i;ww[xu]=w;
                add(u,xu);add(xu,u);
                add(v,xu);add(xu,v);
            }
            else {keu=u;kev=v;kew=w;kex=i;}
        }
        n<<=1;
        dfs1(1,1);dfs2(1,1);build(1,n,1);
        int ans=0;
        while(q--)
        {
            op=read(),u=read(),v=read();
            if(op==1)
            {
                if(u==kex) kew=v;
                else update(id[u+(n>>1)],v,1,n,1);
            }
            else
            {
                ans=query_tree(u,v);
                printf("%d
    ",min(ans,kew+min(query_tree(u,keu)+query_tree(v,kev),query_tree(u,kev)+query_tree(v,keu))));
            }
        }
        return 0;
    }
  • 相关阅读:
    [BZOJ2038]小Z的袜子
    [BZOJ5016]一个简单的询问
    [BZOJ1008][HNOI2008]越狱
    [FZU2254]英语考试
    利用Map 的merge方法统计数量
    List 原生态类型
    try-with-resource 关闭 io流
    利用构建器创建对象
    linux 安装 vault
    git 上传文件
  • 原文地址:https://www.cnblogs.com/cold-cold/p/10049804.html
Copyright © 2020-2023  润新知