概述
题目链接
题意:
给定一个
n
n
n 个点
n
n
n 条边的图,每条边都权值,有
q
q
q 次操作,一种操作修改一条边的值,另一种操作查询
x
x
x 到
y
y
y 的最短路
(
1
<
=
n
,
q
<
=
1
e
5
)
(1<=n,q<=1e5)
(1<=n,q<=1e5)
思路:
如果是一颗树那么这个问题可以被树剖加线段树轻松的解决,已知这张图实际上是一棵树加上一条边构成,那么可以将其删掉一条边 ( u , v ) (u,v) (u,v) 变成一颗树进行处理。那么现在查询 x → y x to y x→y 的最短路,可以分成三种情况,一种直接从树上走 x → l c a ( x , y ) → y x to lca(x,y) to y x→lca(x,y)→y,一种经过 u → v u to v u→v 即 x → u → v → y x to u to v to y x→u→v→y,另一种反过来 x → v → u → y x to v to u to y x→v→u→y ,取一个最小值即可。
代码:
#include <bits/stdc++.h>
#define ll long long
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=3e5+10;
int TT,n,q,op,x,y,U,V,W;
int bq[N],dq[N],dy[N];//边权和点权,将边权放到深度更大的点上,保存对应关系
//树链剖分
struct edge{
int to,next,id,w;
}e[N*2];
int cnt,head[N];
void add(int u,int v,int w,int id){
e[++cnt].to=v;e[cnt].next=head[u];e[cnt].id=id;e[cnt].w=w;head[u]=cnt++;
}
int tot[N],son[N],deep[N],fa[N];
int dfs1(int u,int f,int dep){
tot[u]=1;fa[u]=f;deep[u]=dep;
int pd=-1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==f)continue;
dq[v]=bq[e[i].id];dy[e[i].id]=v;
tot[u]+=dfs1(v,u,dep+1);
if(tot[v]>pd)pd=tot[v],son[u]=v;
}
return tot[u];
}
int idx[N],top[N],id[N],cnt1;
void dfs2(int u,int f){
idx[u]=++cnt1,id[cnt1]=u;
top[u]=f;
if(!son[u])return ;
dfs2(son[u],f);
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(!idx[v])dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
//线段树
struct node{
int l,r;
ll sum;
}T[N*4];
void up(int x){
T[x].sum=T[ls].sum+T[rs].sum;
}
void built(int x,int l,int r){
T[x].l=l;T[x].r=r;
if(l==r){
T[x].sum=dq[id[l]];return ;
}
int mid=(l+r)/2;
built(ls,l,mid);built(rs,mid+1,r);
up(x);
}
void add(int x,int pos,ll val){
if(T[x].l==T[x].r){
T[x].sum=val;return ;
}
int mid=(T[x].l+T[x].r)/2;
if(pos<=mid)add(ls,pos,val);
else add(rs,pos,val);
up(x);
}
ll query(int x,int LL,int RR){
if(T[x].l>=LL&&T[x].r<=RR){
return T[x].sum;
}
int mid=(T[x].l+T[x].r)/2;
ll ans=0;
if(LL<=mid)ans+=query(ls,LL,RR);
if(RR>mid)ans+=query(rs,LL,RR);
return ans;
}
ll ljsum(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
ans+=query(1,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
ans+=query(1,idx[x],idx[y]);
//cout<<x<<endl;
ans-=dq[x];//lca的边权被计算,应该减去
return ans;
}
void init(int n){
memset(head,-1,sizeof(head));cnt=cnt1=0;
for(int i=1;i<=n;i++)idx[i]=id[i]=top[i]=fa[i]=deep[i]=son[i]=tot[i]=dy[i]=dq[i]=0;
}
int main()
{
scanf("%d",&TT);
while(TT--){
scanf("%d%d",&n,&q);init(n);
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,i);add(v,u,w,i);bq[i]=w;
}
dfs1(1,0,1);dfs2(1,0);built(1,1,n);
scanf("%d%d%d",&U,&V,&W);//删去一条边
while(q--){
scanf("%d%d%d",&op,&x,&y);
if(op==0){
if(x!=n)add(1,idx[dy[x]],y),dq[dy[x]]=y;
else W=y;
}else{
ll ans1=ljsum(x,y);//3种情况讨论
ll ans2=ljsum(x,U)+W+ljsum(V,y);
ll ans3=ljsum(x,V)+W+ljsum(U,y);
printf("%lldn",min(ans1,min(ans2,ans3)));
}
}
}
}
最后
以上就是会撒娇星星为你收集整理的HDU 6393 Traffic Network in Numazu (树剖+线段树)的全部内容,希望文章能够帮你解决HDU 6393 Traffic Network in Numazu (树剖+线段树)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复