首页 > 其他分享 >题解:AT_abc294_g [ABC294G] Distance Queries on a Tree

题解:AT_abc294_g [ABC294G] Distance Queries on a Tree

时间:2024-12-22 16:30:25浏览次数:9  
标签:Distance dist int 题解 ABC294G son lca x1 节点

题目链接

https://www.luogu.com.cn/problem/AT_abc294_g

分析

先不考虑修改。

设 \(dist_i\) 表示从根节点到第 \(i\) 号节点的距离,\(\operatorname{lca(u,v)}\) 表示树上两点 \(u,v\) 的最近公共祖先,那么 \(u,v\) 两点间的距离就是 \((dist_{\operatorname{lca(u,v)}}-dist_u)+(dist_{\operatorname{lca(u,v)}}-dist_v)\),即 \(dist_u+dist_v-dist_{\operatorname{lca(u,v)}}\times 2\)。

对于修改操作,考虑使用 dfs 序。

设 \(in_i\) 表示节点 \(i\) 入栈的时间戳,\(out_i\) 表示节点 \(i\) 出栈的时间戳,那么节点 \(i\) 的子树在新的线性序列上对应的区间就是 \([in_i,out_i]\)。

对于一条要被修改的边,设 \(x_1\) 表示原来的权值,\(x_2\) 表示修改后的权值,\(son\) 表示这条边上远离根节点的端点,那么就可以将新的线性序列上的区间 \([in_{son},out_{son}]\) 都作 \(-x_1+x_2\) 的操作,即对节点 \(son\) 的子树上的每一个点到根节点的距离,都 \(-x_1\)(消除原来边的影响)在 \(+x_2\)(加上新边的权值)。

可以使用差分 + 树状数组快速实现对序列的区间修改。

本题中距离最多可达到 \(2 \times 10^{14}\),需要开 long long

细节内容见代码注释。

Code

#include<bits/stdc++.h>
#define i64 long long
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;

const int N=2e5;
int n,q;

int tot_edge,hd[N+5];
struct Edge{int frm,to;i64 val;int lst;}g[N*2+5];
void add_edge(int u,int v,i64 w){
	g[++tot_edge]=Edge{u,v,w,hd[u]};
	hd[u]=tot_edge;
}

int tim,inn[N+5],outt[N+5];
int dep[N+5],f[N+5][30];
//dfs 序 + LCA 预处理 
void dfs(int x,int fa){
	inn[x]=++tim;
	
	dep[x]=dep[fa]+1,f[x][0]=fa;
	for(int i=1;i<=25;++i)
		f[x][i]=f[f[x][i-1]][i-1];
	
	for(int i=hd[x];~i;i=g[i].lst)
		if(g[i].to^fa)dfs(g[i].to,x);
	
	outt[x]=tim;
	return;
}

//倍增求 LCA 
int Lca(int x,int y){
	if(dep[x]<dep[y])x^=y,y^=x,x^=y;
	
	for(int i=25;~i;--i)
		if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	
	for(int i=25;~i;--i)
		if(f[x][i]^f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}

//树状数组 
i64 tr[N+5];
int lowbit(int x){return x&-x;}
void upd(int x,i64 v){
	for(int i=x;i<=n;i+=lowbit(i))
		tr[i]+=v;
	return;
}
i64 ask(int x){
	i64 res=0;
	for(int i=x;i;i-=lowbit(i))
		res+=tr[i];
	return res;
}

int main(){
	ios::sync_with_stdio(false),
	cin.tie(0),cout.tie(0);
	memset(hd,-1,sizeof hd);
	
	int op,x1,x2,x3;
	
	cin>>n;
	for(int i=1;i<n;++i){
		cin>>x1>>x2>>x3;
		add_edge(x1,x2,x3),
		add_edge(x2,x1,x3);
	}
	
	dfs(1,0);
	
	//预处理每个点到根节点的距离 
	for(int i=1;i<=tot_edge;i+=2){
		x1=g[i].frm,x2=g[i].to;
		
		//寻找远离根节点的端点 
		if(dep[x1]<dep[x2])
			//相当于 swap(x1,x2) 
			x1^=x2,x2^=x1,x1^=x2;
		
		//将子树上每一个点到根节点的距离都加上这条边的权值 
		upd(inn[x1],g[i].val),
		upd(outt[x1]+1,-g[i].val);
	}
	
	cin>>q;
	while(q--){
		cin>>op>>x1>>x2;
		
		//修改 
		if(op==1){
			x1*=2;//链式前向星存的是双向边,应将编号 *2 
			int u=g[x1].frm,v=g[x1].to;
			//找到远离根节点的端点 
			if(dep[u]<dep[v])u^=v,v^=u,u^=v;
			
			//消除原边影响 
			upd(inn[u],-g[x1].val),
			upd(outt[u]+1,g[x1].val);
			
			//加上新边权值 
			upd(inn[u],x2),
			upd(outt[u]+1,-x2);
			g[x1].val=x2;
		}
		//查询 
		else{
			x3=Lca(x1,x2);
			
			cout<<ask(inn[x1])+ask(inn[x2])-ask(inn[x3])*2<<'\n';
		}
	}
	return 0;
}

标签:Distance,dist,int,题解,ABC294G,son,lca,x1,节点
From: https://www.cnblogs.com/ezhe/p/18622238

相关文章

  • CF2040D 题解
    构造题做得较少,所以性质观察得较慢。值域给的\(2n\)非常诡异,想到考虑\(2\)的倍数。按深度记录下每层结点,发现隔一层依次按\(2\)的倍数填充,即可满足。即:先填奇数层,再填偶数层。但是连续的偶数是不能相邻的,发现当深度在\([2,4]\)时,无论以何顺序按层填充,都会有问题。处......
  • 洛谷 P11411 兰奇的卡牌游戏——题解
    洛谷P11411兰奇的卡牌游戏传送锚点摸鱼环节兰奇的卡牌游戏题目描述作为制卡大师的兰奇,发明了一种自助型卡牌游戏。给定\(n\)张卡牌,第\(i\)张卡牌编号为\(i\),其权值为\(a_i\),卡牌的权值互不相同。这个卡牌游戏的规则需要自己生成。一开始,所有的牌都在备选区。从备选......
  • CF1548A Web of Lies 题解
    WebofLies题解洛谷。Codeforces。题意比较直接,就不复述了。思路分析题意首先根据操作3,删人只是暂时的,可以分析出每次删的人对于后面都没有影响。关注到这个词:执行以下操作直至不可再执行为止。显然,在整个图中所有该被删除的人都逃不掉,迟早被删除。那么看看什么样......
  • P8060 [POI2003] Sums 题解
    题目传送门前置知识同余最短路解法考虑同余最短路,设\(dis_{i}\)表示\(\bmoda_{1}=i\)时能被拼成的最小值,接着只需要判断是否有\(dis_{b\bmoda_{1}}\leb\)即可。直接建边的空间复杂度为\(O(nV)\),无法接受。但我们发现边不一定非要建出来,可以在Dijsktra松弛时枚......
  • 题解 - 冰壶比赛
    题目描述在3月29日举行的女子冰壶世锦赛决赛中,王冰玉、柳荫、岳清爽和周妍组成的中国女子冰壶队以8比6击败了冬奥会和世锦赛双冠王瑞典队,夺得了中国冰壶历史上第一枚世锦赛金牌,创造了历史。美丽、实力兼具的中国冰壶姑娘们也赢得了超高的赞誉。在冰壶比赛中,给出一个目标点......
  • 平民玩家体验《诛仙世界》进副本闪退频现?游戏问题解决当选云电脑
    嘿嘿,千盼万盼《诛仙世界》终于开服了!还有人没收到消息吗?这款游戏的虚幻5引擎非常的劲爆,对于经常玩一些3A大作的玩家都知道,这无疑是目前最好的游戏引擎,所打造出来的诛仙世界的画质也是相当顶级的。在开服的第一天,一些服务器的人数大幅激增;其中《风华绝代》的排队人数竟已超过12......
  • CF2049D 题解
    CF2049D题解题意给定一个\(n\timesm\)的数字矩阵和常数\(K\),初始位于\((1,1)\)点,只能通过向下或者向右走来到达\((n,m)\)点。存在某种操作,可以选择任意一行,将其所有列元素逆时针旋转\(1\)个单位,这个操作可以对任意行进行任意次(下面称这个操作为“旋转”)。设最后......
  • CF2049C 题解
    CF2049C题解关于MEX的构造题。题意有一个\(n\)元环,每个元素都和它的相邻元素是“朋友”。此外,额外给定一组\(x,y\),\(x\)和\(y\)彼此也是“朋友”。求一种给\(n\)个元素填数的方案,使得对于任意一个\(i\in[1,n]\),填在\(i\)这个位置的数\(a_i\),是它所有“朋友”的......
  • redis-cli (error) NOAUTH Authentication required问题解决
    1.查找redis-cli所在目录whichredis-cli2.切换到redis-cli目录3.切换到usr/bin目录执行以下命令redis-cli-hip-pport4.验证redis登录密码auth'password'5.获取redis数据......
  • Luogu P8112 [Cnoi2021] 符文破译 题解 [ 蓝 ] [ KMP ] [ 线性 dp ] [ 决策单调性 dp
    符文破译:KMP+dp的好题。暴力dp不难打出一个暴力dp:设计\(dp_i\)表示当前前\(i\)位全部完成了匹配,所需的最小分割数。转移也是简单的,我们在KMP的过程中进行dp转移,每次选取next不断跳向再前面的next,然后进行转移即可。很显然一个字符集大小为\(1\)的串就能轻松......