ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

#树链剖分,并查集,树状数组#洛谷 4949 最短距离

2020-02-19 14:03:21  阅读:235  来源: 互联网

标签:洛谷 剖分 rr int 查集 son fa dfn ls


题目大意

给出一个基环树,支持修改边权和查询两点间最短距离


分析

如果是一棵树那就很简单了,树链剖分,将边权变成子节点的点权,然后因为只有单边修改,所以可以用常数比较小的树状数组;
但是这是一棵基环树,考虑将环上的一条边拎出来,对其它边用树的方法做\(x->y\),这条边特判,也就是\(x->zx->zy->y\)或者\(x->zy->zx->y\),一共三种情况求最小值,注意查询时的区间边界


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011; struct node{int y,w,next;}e[N<<1];
int c[N],a[N],dep[N],dfn[N],top[N],f[N];
int fat[N],big[N],son[N],ls[N],tot,n,m,K=1,zx,zy,zw,zp;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
inline void add(int x,int y){for (;x<=n;x+=-x&x) c[x]+=y;}
inline signed query(int x){rr int ans=0; for (;x;x-=-x&x) ans+=c[x]; return ans;}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline signed Query(int x,int y){
    rr int ans=0;
    while (top[x]!=top[y]){
        if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
        ans+=query(dfn[x])-query(dfn[top[x]]-1);
        x=fat[top[x]];
    }
    if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
    return ans+=query(dfn[y])-query(dfn[x]);//[dfn[x]+1~dfn[y]]最上面的点权不算
}
inline void dfs1(int x,int fa,int W){
    dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1,c[x]=W;
    for (rr int i=ls[x],mson=-1;i;i=e[i].next)
    if (e[i].y!=fa){
        dfs1(e[i].y,x,e[i].w);
        son[x]+=son[e[i].y];
        if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];
    }
}
inline void dfs2(int x,int linp){
    dfn[x]=++tot,a[tot]=c[x],top[x]=linp;
    if (!big[x]) return; dfs2(big[x],linp);
    for (rr int i=ls[x];i;i=e[i].next)
    if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,e[i].y);
}
signed main(){
    n=iut(); m=iut();
    for (rr int i=1;i<=n;++i) f[i]=i;
    for (rr int i=1;i<=n;++i){
        rr int x=iut(),y=iut(),w=iut();
        rr int fa=getf(x),fb=getf(y);
        if (fa==fb) {zx=x,zy=y,zw=w,zp=i,K+=2; continue;}
        if (fa>fb) fa^=fb,fb^=fa,fa^=fb; f[fa]=fb;
        e[++K]=(node){y,w,ls[x]},ls[x]=K;
        e[++K]=(node){x,w,ls[y]},ls[y]=K;
    }
    dfs1(1,0,0),dfs2(1,1);
    for (rr int i=1;i<=n;++i) c[i]=c[i-1]+a[i];
    for (rr int i=n;i>=1;--i) c[i]-=c[i&(i-1)];//O(n)预处理树状数组
    for (rr int i=1;i<=m;++i){
        rr int op=iut(),x=iut(),y=iut();
        if (op==1){
            if (x==zp) zw=y;
            else{
                rr int xx=e[x<<1].y,yy=e[x<<1|1].y;
                if (dep[xx]<dep[yy]) xx^=yy,yy^=xx,xx^=yy;
                add(dfn[xx],y-a[dfn[xx]]),a[dfn[xx]]=y;
            }
        }else{
            rr int t1=Query(x,zx)+Query(y,zy);
            rr int t2=Query(x,zy)+Query(y,zx);
            rr int ans1=Query(x,y),ans2=(t1<t2?t1:t2)+zw;
            print(ans1<ans2?ans1:ans2),putchar(10);
        }
    }
    return 0;
}

标签:洛谷,剖分,rr,int,查集,son,fa,dfn,ls
来源: https://www.cnblogs.com/Spare-No-Effort/p/12331023.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有