HDU6393(LCA + RMQ + 树状数组) n边图,两点最短距离 , 修改边权
题意:
一个n个点,n条边的图,2中操作,1是将某条边的权值更改,2是询问两点的最短距离。
题解:
由于n个点,n条边,所以是树加一个环,将环上的边随意取出一条,就是1颗树,以取出的边的一个端点为根,建立有根树。虚线就是取出的边。红色为环上的边。
对于更改边的权值的操作,用dfs序+区间修改点查询的树状树组维护。
对于询问最短路的操作,用LCA分类解决。假设询问的两点是x、y,LCA是 z。
若z不是环上的点,那么最短路就是:x到根的距离+y到根的距离-z到根的距离*2;
若z是环上的点,最短路可能是经过图中红线的路径,也可能是经过图中虚线的路径,取最短的即可
#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1) using namespace std;
typedef long long ll;
const int N =1e5+; struct node
{
int u,v,next;
int id,f;
ll w;
}edge[N*]; struct node1
{
int l,r;
ll w;
ll lz;
}tr[N<<]; int tot,head[N];
int n,q;
int anc[N<<][]; int dfn;
int dfns[N*];
int dep[N*];
int pos[N];
int inde[N];
int L[N];
int R[N];
int clo; int to[N];
int vis[N];
ll ww[N]; int uu,vv;
ll cost;
int huan;
int idd; void init()
{
tot=;
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
memset(inde,-,sizeof(inde));
memset(pos,-,sizeof(pos));
clo=; huan=; idd=; dfn=; /// dfn竟然没清零 MMP
} void add(int u,int v,ll w,int id)
{
edge[++tot].u=u; edge[tot].v=v; edge[tot].id=id; edge[tot].w=w; edge[tot].f=;
edge[tot].next=head[u]; head[u]=tot;
} void dfs1(int u,int fa)
{
if(vis[u]){
uu=fa; vv=u; huan=; return ;
}
vis[u]=;
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa) continue;
dfs1(v,u);
}
} void dfs2(int u,int deep) /// dfs序
{
//cout<<" u "<<u<<" deep "<<deep<<endl;
dfns[dfn]=u; dep[dfn]=deep; pos[u]=dfn++;
L[u]=++clo;
inde[u]=L[u]; /// 记录u在线段树中的位置
for(int i=head[u];i!=-;i=edge[i].next){
if(edge[i].f) continue; /// 如果是标记的边跳过
int v=edge[i].v;
if(pos[v]==-){
to[edge[i].id]=v; /// 表示这条边指向哪个点?
dfs2(v,deep+);
dfns[dfn]=u; dep[dfn++]=deep;
}
}
R[u]=clo;
} void init_RMQ(int n) /// dfn
{
for(int i=;i<=n;++i) anc[i][]=i;
for(int j=;(<<j)<=n;++j)
for(int i=;i+(<<j)-<=n;++i){
if(dep[anc[i][j-]]<dep[anc[i+(<<(j-))][j-]]) anc[i][j]=anc[i][j-];
else anc[i][j]=anc[i+(<<(j-))][j-];
}
} inline int RMQ(int L,int R)
{
int k=;
while(<<(k+)<=R-L+) ++k;
if(dep[anc[L][k]]<dep[anc[R-(<<k)+][k]]) return anc[L][k];
return anc[R-(<<k)+][k];
} inline int LCA(int u,int v)
{
if(pos[u]>pos[v]) return dfns[RMQ(pos[v],pos[u])];
return dfns[RMQ(pos[u],pos[v])];
} void push_up(int i)
{
tr[i].w=tr[lson].w+tr[rson].w;
} void push_down(int i)
{
if(tr[i].lz){ /// 查询只有点查询,所以不必更新区间点的sum
ll &lz=tr[i].lz;
tr[lson].lz+=lz; tr[rson].lz+=lz;
tr[lson].w+=lz; tr[rson].w+=lz;
lz=;
}
} void build(int i,int l,int r)
{
tr[i].l=l; tr[i].r=r; tr[i].w=; tr[i].lz=;
if(l==r) return ;
int mid=(l+r)>>;
build(lson,l,mid);
build(rson,mid+,r);
} void update(int i,int l,int r,ll w)
{
if(tr[i].l==l&&tr[i].r==r){
tr[i].lz+=w; tr[i].w+=w;
return ;
}
push_down(i);
int mid=(tr[i].l+tr[i].r)>>;
if(r<=mid) update(lson,l,r,w);
else if(l>mid ) update(rson,l,r,w);
else{
update(lson,l,mid,w);
update(rson,mid+,r,w);
}
push_up(i);
} ll query(int i,int aim)
{
if(tr[i].l==tr[i].r&&tr[i].l==aim){
return tr[i].w;
}
push_down(i);
int mid=(tr[i].l+tr[i].r)>>;
if(aim<=mid) return query(lson,aim);
else return query(rson,aim);
} ll getans(int u,int v)
{
int lca=LCA(u,v);
ll sum1,sum2,sum3;
sum1=query(,L[u]); sum2=query(,L[v]);
sum3=query(,L[lca]);
return sum1+sum2-sum3*;
} int main()
{
int T;
int u,v,op;
ll w;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&q);
init();
for(int i=;i<=n;i++){
scanf("%d %d %lld",&u,&v,&w);
add(u,v,w,i);
add(v,u,w,i);
ww[i]=w;
} dfs1(,-);/// 第一遍dfs 先找到环中的任意一条边
for(int i=;i<=tot;i++){ /// 给边打上标记
if((edge[i].u==uu&&edge[i].v==vv)||(edge[i].u==vv&&edge[i].v==uu)){
edge[i].f=;
idd=edge[i].id;
cost=edge[i].w;
}
}
dfs2(,);
/*cout<<"dfn "<<dfn<<endl;
cout<<uu<<" *** "<<vv<<endl;
for(int i=1;i<=n;i++){
cout<<"l "<<L[i]<<" r "<<R[i]<<endl;
}
*/
init_RMQ(dfn); build(,,n); /// 以dfs的遍历出的 L,R 建树 那么接下来就是一个区间更新,单点查询的问题了
for(int i=;i<=n;i++){
if(i==idd) continue;
u=to[i];
update(,L[u],R[u],ww[i]);
}
/*
for(int i=1;i<=n;i++){
ll tmp=query(1,L[i]);
cout<<" dis "<<tmp<<endl;
}
*/ while(q--)
{
scanf("%d",&op);
if(op==){
scanf("%d %lld",&u,&w);
if(u==idd){ /// 如果是标记的环中的边,那么就没必要更新线段树
ww[u]=w;
}
else{
int tmp=to[u];
//cout<<"tmp "<<tmp<<" L "<<L[tmp]<<" R "<<R[tmp]<<" w "<<ww[u]<<endl;
update(,L[tmp],R[tmp],-ww[u]);
ww[u]=w;
update(,L[tmp],R[tmp],ww[u]);
}
}
else{
scanf("%d %d",&u,&v);
ll ans=getans(u,v);
ans=min(ans,getans(uu,u)+getans(vv,v)+cost); /// 经过标记的路的两个不同的方向。
ans=min(ans,getans(uu,v)+getans(vv,u)+cost);
printf("%lld\n",ans);
}
} }
return ;
}
HDU6393(LCA + RMQ + 树状数组) n边图,两点最短距离 , 修改边权的更多相关文章
- POJ 2763 (LCA +RMQ+树状数组 || 树链部分) 查询两点距离+修改边权
题意: 知道了一颗有 n 个节点的树和树上每条边的权值,对应两种操作: 0 x 输出 当前节点到 x节点的最短距离,并移动到 x 节点位置 1 x val 把第 x 条边的权值改为 ...
- UESTC 912 树上的距离 --LCA+RMQ+树状数组
1.易知,树上两点的距离dis[u][v] = D[u]+D[v]-2*D[lca(u,v)] (D为节点到根节点的距离) 2.某条边<u,v>权值一旦改变,将会影响所有以v为根的子树上的 ...
- POJ - 2763 Housewife Wind (树链剖分/ LCA+RMQ+树状数组)
题意:有一棵树,每条边给定初始权值.一个人从s点出发.支持两种操作:修改一条边的权值:求从当前位置到点u的最短路径. 分析:就是在边可以修改的情况下求树上最短路.如果不带修改的话,用RMQ预处理LCA ...
- HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)
这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带 ...
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
- hdu5293 lca+dp+树状数组+时间戳
题意是给了 n 个点的树,会有m条链条 链接两个点,计算出他们没有公共点的最大价值, 公共点时这样计算的只要在他们 lca 这条链上有公共点的就说明他们相交 dp[i]为这个点包含的子树所能得到的最 ...
- 【BZOJ】1699: [Usaco2007 Jan]Balanced Lineup排队(rmq/树状数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=1699 我是用树状数组做的..rmq的st的话我就不敲了.. #include <cstdio& ...
- 【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更 ...
- hdu 5497 Inversion 树状数组 逆序对,单点修改
Inversion Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5497 ...
随机推荐
- 小程序为什么脚本内不能使用window等对象
小程序(应用号)内不能使用window等对象. 页面的脚本逻辑在是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能再脚本中使用window,也无法在脚本中操作组件.
- Web网站的几个QPS
评价一个网站的"大小",处于视角的不同,有很多种衡量的方法,类似文章数,页面数之类的数据非常明显,也没有什么可以争议的.但对于并发来说,争议非常之多,这里就从一个技术的角度开始,谈 ...
- Python pip命令
一.简介 pip 是一个安装和管理 Python 包的工具 , 是 easy_install 的一个替换品.distribute是setuptools的取代(Setuptools包后期不再维护了),p ...
- 运行maven build报错No goals have been specified for this build.
运行maven报错: [ERROR] No goals have been specified for this build. You must specify a valid lifecycle p ...
- 很好的QSqlDatabase问题说明,关于连接错误(转)
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connect ...
- mysql_init调用卡住原因分析
有同学做类似如下的操作: class X { public: X() // 类X的构造函数ctor { _mysql_handler = mysql_init(NULL); } }; // 定义类X的 ...
- QT背景
Qt是一个跨平台的C++图形用户界面应用程序框架.它为应用程序开发者提供建立基于window界面所需的功能. Qt是诺基亚公司的一个产品.1996年,Qt进入商业领域,已成为全世界范围内数千种成功的应 ...
- Maven类包冲突终极三大解决技巧 mvn dependency:tree
Maven对于新手来说是<步步惊心>,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫. Maven对于老手来说是<真爱配方>,因为它无所不能 ...
- 如何杀死一个已经detached的screen会话?
如果向杀死一个已经detached的screen会话,可以使用以下命令: screen -X -S seesion-id quit 举例如下: [root@localhost ~]# screen - ...
- Digester学习笔记(一)转载
本博文系转载,作者原文已经无法找到,感谢原作者的辛苦整理 Digester学习笔记(一) 在windows下开发程序,用M$提供的接口处理.ini文件或管理注册表的键值是非常方便的.在java平台上开 ...