题意:给定一个带权边无向基环树,有两种操作,一种是改变某个边的权值,另一种是询问两点间的最短路径。

可以对环进行缩点,以环为根建立一棵新树,并记录与环相连的所有点和环上的哪个点相连,将路径分为环外和环内的两类进行处理。环外的路径可以用树剖+树状数组维护,环内的路径复制一倍,用另一个树状数组维护。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int hd[N],n,m,ne,sta[N],tp,vis[N],id[N],anc[N],lid[N],nl;
int fa[N],son[N],siz[N],dep[N],top[N],bg[N],ed[N],rnk[N],tot;
struct E2 {int u,v,c;} e2[N];
struct E {int v,c,nxt;} e[N<<];
struct BIT {
ll c[N<<];
int n;
int lb(int x) {return x&-x;}
void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;}
ll get(int u) {ll ret=; for(; u; u-=lb(u))ret+=c[u]; return ret;}
ll sum(int l,int r) {return get(r)-get(l-);}
void init(int _n) {memset(c,,sizeof c),n=_n;}
} tr1,tr2;
void addedge(int u,int v,int c) {e[ne]= {v,c,hd[u]},hd[u]=ne++;}
bool isloop(int u) {return id[u]==n+;}
bool dfs_loop(int u,int f) {
if(vis[u]) {
while(!lid[u]) {
int v=sta[tp--];
id[v]=n+,lid[v]=++nl;
}
return ;
}
vis[u]=,sta[++tp]=u;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==f)continue;
if(dfs_loop(v,u))return ;
}
tp--;
return ;
}
void dfs_anc(int u,int f,int a) {
anc[u]=a;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==f||isloop(v))continue;
dfs_anc(v,u,a);
}
}
void dfs_chain_1(int u,int f,int d) {
fa[u]=f,son[u]=,siz[u]=,dep[u]=d;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u]||isloop(v))continue;
dfs_chain_1(v,u,d+),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs_chain_2(int u,int tp) {
top[u]=tp,bg[u]=++tot,rnk[bg[u]]=u;
if(son[u])dfs_chain_2(son[u],tp);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u]||v==son[u]||isloop(v))continue;
dfs_chain_2(v,v);
}
ed[u]=tot;
}
void upd(int u,int v,int x) {
if(isloop(u)&&isloop(v)) {
int l=lid[u],r=lid[v];
if(l>r)swap(l,r);
if(r-l!=)swap(l,r);
tr2.add(r,-tr2.sum(r,r)),tr2.add(r+nl,-tr2.sum(r+nl,r+nl));
tr2.add(r,x),tr2.add(r+nl,x);
} else {
int l=bg[id[u]],r=bg[id[v]];
if(l>r)swap(l,r);
tr1.add(r,-tr1.sum(r,r)),tr1.add(r,x);
}
}
ll qry_loop(int u,int v) {
int l=lid[u],r=lid[v];
if(l>r)swap(l,r);
return min(tr2.sum(l+,r),tr2.sum(r+,l+nl));
}
ll qry_tree(int u,int v) {
int ancu=anc[u],ancv=anc[v];
u=id[u],v=id[v];
ll ret=;
for(; top[u]!=top[v]; u=fa[top[u]]) {
if(dep[top[u]]<dep[top[v]])swap(u,v);
ret+=tr1.sum(bg[top[u]],bg[u]);
}
if(dep[u]<dep[v])swap(u,v);
ret+=tr1.sum(bg[v]+,bg[u]);
ret+=qry_loop(ancu,ancv);
return ret;
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
memset(hd,-,sizeof hd),ne=tp=nl=tot=;
memset(vis,,sizeof vis);
scanf("%d%d",&n,&m);
for(int i=; i<=n; ++i) {
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c),addedge(v,u,c);
e2[i]= {u,v,c};
}
for(int i=; i<=n; ++i)id[i]=i;
dfs_loop(,),id[n+]=n+;
for(int u=; u<=n; ++u)if(isloop(u))dfs_anc(u,,u);
for(int u=; u<=n; ++u)if(isloop(u)) {
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(!isloop(v))addedge(n+,v,e[i].c);
}
}
dfs_chain_1(n+,,),dfs_chain_2(n+,n+);
tr1.init(tot),tr2.init(nl*);
for(int i=; i<=n; ++i)upd(e2[i].u,e2[i].v,e2[i].c);
while(m--) {
int f,a,b;
scanf("%d%d%d",&f,&a,&b);
if(f==)upd(e2[a].u,e2[a].v,b);
else printf("%lld\n",qry_tree(a,b));
}
}
return ;
}

也可以LCA+差分维护每个点到根节点的距离,复杂度少了个log(但实际速度差不了多少)

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int hd[N],n,m,ne,sta[N],tp,vis[N],id[N],anc[N],lid[N],nl;
int fa[N],son[N],siz[N],dep[N],top[N],bg[N],ed[N],rnk[N],tot;
struct E2 {int u,v,c;} e2[N];
struct E {int v,c,nxt;} e[N<<];
struct BIT {
ll c[N<<];
int n;
int lb(int x) {return x&-x;}
void add(int u,int x) {for(; u<=n; u+=lb(u))c[u]+=x;}
ll get(int u) {ll ret=; for(; u; u-=lb(u))ret+=c[u]; return ret;}
ll sum(int l,int r) {return get(r)-get(l-);}
void init(int _n) {memset(c,,sizeof c),n=_n;}
} tr1,tr2;
void addedge(int u,int v,int c) {e[ne]= {v,c,hd[u]},hd[u]=ne++;}
bool isloop(int u) {return id[u]==n+;}
bool dfs_loop(int u,int f) {
if(vis[u]) {
while(!lid[u]) {
int v=sta[tp--];
id[v]=n+,lid[v]=++nl;
}
return ;
}
vis[u]=,sta[++tp]=u;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==f)continue;
if(dfs_loop(v,u))return ;
}
tp--;
return ;
}
void dfs_anc(int u,int f,int a) {
anc[u]=a;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==f||isloop(v))continue;
dfs_anc(v,u,a);
}
}
void dfs_chain_1(int u,int f,int d) {
fa[u]=f,son[u]=,siz[u]=,dep[u]=d;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u]||isloop(v))continue;
dfs_chain_1(v,u,d+),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs_chain_2(int u,int tp) {
top[u]=tp,bg[u]=++tot,rnk[bg[u]]=u;
if(son[u])dfs_chain_2(son[u],tp);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(v==fa[u]||v==son[u]||isloop(v))continue;
dfs_chain_2(v,v);
}
ed[u]=tot;
}
void upd(int u,int v,int x) {
if(isloop(u)&&isloop(v)) {
int l=lid[u],r=lid[v];
if(l>r)swap(l,r);
if(r-l!=)swap(l,r);
tr2.add(r,x),tr2.add(r+nl,x);
} else {
u=id[u],v=id[v];
if(fa[u]==v)swap(u,v);
tr1.add(bg[v],x),tr1.add(ed[v]+,-x);
}
}
ll qry_loop(int u,int v) {
int l=lid[u],r=lid[v];
if(l>r)swap(l,r);
return min(tr2.sum(l+,r),tr2.sum(r+,l+nl));
}
ll qry_tree(int u,int v) {
int ancu=anc[u],ancv=anc[v];
u=id[u],v=id[v];
ll ret=tr1.get(bg[u])+tr1.get(bg[v]);
for(; top[u]!=top[v]; u=fa[top[u]])
if(dep[top[u]]<dep[top[v]])swap(u,v);
if(dep[u]<dep[v])swap(u,v);
ret-=*tr1.get(bg[v]);
ret+=qry_loop(ancu,ancv);
return ret;
}
int main() {
int T;
for(scanf("%d",&T); T--;) {
memset(hd,-,sizeof hd),ne=tp=nl=tot=;
memset(vis,,sizeof vis);
scanf("%d%d",&n,&m);
for(int i=; i<=n; ++i) {
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c),addedge(v,u,c);
e2[i]= {u,v,c};
}
for(int i=; i<=n; ++i)id[i]=i;
dfs_loop(,),id[n+]=n+;
for(int u=; u<=n; ++u)if(isloop(u))dfs_anc(u,,u);
for(int u=; u<=n; ++u)if(isloop(u)) {
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
if(!isloop(v))addedge(n+,v,e[i].c);
}
}
dfs_chain_1(n+,,),dfs_chain_2(n+,n+);
tr1.init(tot),tr2.init(nl*);
for(int i=; i<=n; ++i)upd(e2[i].u,e2[i].v,e2[i].c);
while(m--) {
int f,a,b;
scanf("%d%d%d",&f,&a,&b);
if(f==)upd(e2[a].u,e2[a].v,b-e2[a].c),e2[a].c=b;
else printf("%lld\n",qry_tree(a,b));
}
}
return ;
}

HDU - 6393 Traffic Network in Numazu (基环树+树链剖分/LCA)的更多相关文章

  1. hdu 6393 Traffic Network in Numazu (树链剖分+线段树 基环树)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=6393 思路:n个点,n条边,也就是基环树..因为只有一个环,我们可以把这个环断开,建一个新的点n+1与之相 ...

  2. HDU - 6393 Traffic Network in Numazu(树链剖分+基环树)

    http://acm.hdu.edu.cn/showproblem.php?pid=6393 题意 给n个点和n条边的图,有两种操作,一种修改边权,另一种查询u到v的最短路. 分析 n个点和n条边,实 ...

  3. HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)

    这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带 ...

  4. Traffic Network in Numazu

    Traffic Network in Numazu 题目描述 Chika is elected mayor of Numazu. She needs to manage the traffic in ...

  5. hdu6393 Traffic Network in Numazu 树链剖分

    题目传送门 题意:给出n个点n条边的无向带权图,再给出两种操作,操作1是将第x条边的边权修改为y,操作2是询问点x到点y的最短路径. 思路:如果是n个点n-1条边,题目就变成了树,修改边权和询问最短路 ...

  6. 【BZOJ 2791】 2791: [Poi2012]Rendezvous (环套树、树链剖分LCA)

    2791: [Poi2012]Rendezvous Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组询问由两 ...

  7. CodeForces 916E Jamie and Tree(树链剖分+LCA)

    To your surprise, Jamie is the final boss! Ehehehe. Jamie has given you a tree with n vertices, numb ...

  8. NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分

    原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...

  9. 【BZOJ】2819: Nim(树链剖分 / lca+dfs序+树状数组)

    题目 传送门:QWQ 分析 先敲了个树链剖分,发现无法AC(其实是自己弱,懒得debug.手写栈) 然后去学了学正解 核心挺好理解的,$ query(a) $是$ a $到根的异或和. 答案就是$ l ...

随机推荐

  1. Django与Session

    Session Session的由来 ​ Cookie虽然在一定程度上解决了"保持状态"的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能 ...

  2. Shell脚本中的shebang到底是什么

    使用类Unix系统的同学可能都对"#!"这个符号并不陌生,但是你真的了解它吗? 这个符号的名称,叫做"Shebang"或者"Sha-bang" ...

  3. 好用的 Chrome 插件

    这些好用的 Chrome 插件,提升你的工作效率   本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可 ...

  4. 【有奖征集】报表模板库邀您提反馈,轻松赢取P30!

    >>立即参赛 赛事初衷 大数据时代,数据的价值愈发彰显,什么样的报表才能真正帮助业务决策?这几乎是所有信息化建设的企业和个人都在思考的问题. 作为报表领域标杆企业,葡萄城于2017年推出了 ...

  5. 查找担保圈-step3-获取担保圈路径

    USE [test] GO /****** Object: StoredProcedure [dbo].[p01_get_group_path] Script Date: 2019/7/8 14:40 ...

  6. C++学习 之 类中的特殊函数和this指针(笔记)

    1.构造函数 构造函数是一种特殊的函数,它在对象被创建时被调用,与类同名无返回类型,可以被重载.构造函数的可以在类内实现也可以在类外实现. 构造函数的声明类似于下面的代码: class Human { ...

  7. JavaScript刷新事件

    1, Location reload() 方法 2,

  8. Jconsole与Jmx 分析JVM状况(下) 转

    出处: Jconsole与Jmx 分析JVM状况(下) 线程(ThreadMXBean ) 从 Jconsole 画面取得线程画面如下: 左下角列出了所以正在运行的线程.通过点击某个线程,右下脚可以看 ...

  9. WordPress网站搬家数据迁移完整教程

    用本地环境搭建好的WordPress网站在做好之后如何从本地迁移到网络空间或者网络服务器上呢? 首先请确认你在本地建站的时候只做了themes里面的模版文件,如果只是自己改了下模版,那么网站在搬到服务 ...

  10. Codeforces 1178C. Tiles

    传送门 考虑一块块填,首先 $(1,1)$ 有 $4$ 种方案 然后根据 $(1,1)$ 的右边颜色,$(1,2)$ 有两种方案,$(1,3)$ 根据 $(1,2)$ 也有两种方案... 考虑 $(2 ...