P4949 最短距离(树剖)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4949 最短距离(树剖)相关的知识,希望对你有一定的参考价值。

P4949 最短距离(树剖)

n n n个点 n n n条边的无向连通图,显然就是基环树。

考虑断掉环上的一条边,就是树,然后用树剖处理。

无向图判环,并查集即可。

边权转点权,赋给儿子即可,因为每个儿子父亲唯一。

树剖后,转化为区间问题,考虑用BIT。

单点修改,对于断开的那条边直接修改,否则单点修改。

链查询,转化为区间查询即可,注意最后不要加上LCA的那个点权,因为点权是指向父边的,不在查询之中。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = 402653189,805306457,1610612741,998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(nullptr) 
void Print(int *a,int n)
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 

template <typename T>		//x=max(x,y)  x=min(x,y)
void cmx(T &x,T y)
	if(x<y) x=y;

template <typename T>
void cmn(T &x,T y)
	if(x>y) x=y;

int n,q;
int cu,cv,cw,cid;
struct TCS //树链剖分(Tree Chain Subdivision)
#define il inline
	struct edge
		int to,nt,w;
	e[N<<1]; 
	int h[N],cnt;
	void add(int u,int v,int w)
		e[++cnt]=v,h[u],w,h[u]=cnt;
		e[++cnt]=u,h[v],w,h[v]=cnt;
	
	int sz[N],fa[N],son[N],top[N],dfn[N],dep[N];
	void dfs(int u,int f)
		sz[u]=1,fa[u]=f,dep[u]=dep[f]+1;
		for(int i=h[u];i;i=e[i].nt)
			int v=e[i].to;
			if(v==f) continue;
			dfs(v,u);
			sz[u]+=sz[v];
			if(sz[son[u]]<sz[v]) son[u]=v;
		
	
	int id,w[N];
	void dfs1(int u,int tp,int c)
		top[u]=tp,dfn[u]=++id;w[id]=c;
		for(int i=h[u];i;i=e[i].nt)
			int v=e[i].to;
			if(v==son[u])
				 dfs1(v,tp,e[i].w);break; 
				 //必须先访问重链,不然dfn序有问题
			
		
		for(int i=h[u];i;i=e[i].nt)
			int v=e[i].to;
			if(v!=fa[u]&&v!=son[u]) dfs1(v,v,e[i].w);
		
	
#define lowbit(x) x&(-x)	
	int s[N];
	int que(int x)
			int ans=0;
			while(x>=1)
				ans+=s[x];
				x-=lowbit(x);
			
			return ans;
		
		void upd(int x,int y)
			while(x<=n)
				s[x]+=y;
				x+=lowbit(x);
			
		
	int que_c(int x,int y)
		int ans = 0;
		if(x==y) return 0;
		 while(top[x]!=top[y])
		 	if(dep[top[x]]<dep[top[y]]) swap(x,y);
		 	ans+=que(dfn[x])-que(dfn[top[x]]-1);
		 	x=fa[top[x]];
		 
		 if(dep[x]<dep[y]) swap(x,y);
		 ans+=que(dfn[x])-que(dfn[y]);		
		 return ans;
	
	void init()
		dfs(1,0),dfs1(1,1,0);
		rep(i,2,n) upd(i,w[i]);
	
	int solve(int x,int y)
		return min(min(que_c(x,y),que_c(x,cu)+cw+que_c(cv,y)),que_c(x,cv)+cw+que_c(cu,y));
	
T;
struct E
	int u,v,w;
e[N];
int s[N];
int find(int x)
	return s[x]==x?x:s[x]=find(s[x]);

int main()
	scanf("%d%d",&n,&q);
	rep(i,1,n) s[i] = i;
	rep(i,1,n)
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		int fu=find(u),fv=find(v);
		if(fu==fv)
			cu = u,cv = v,cw = w,cid = i;
			continue;
		
		s[fu]=fv;
		e[i] = u,v,w;
		T.add(u,v,w);
	
	T.init();
		while(q--)
			int op,x,y;
			scanf("%d%d%d",&op,&x,&y);
			if(op==1)
				if(x == cid) cw = y;
				else 
					if(T.fa[e[x].u] == e[x].v)
						T.upd(T.dfn[e[x].u],y-e[x].w);
					
					else 
					    T.upd(T.dfn[e[x].v],y-e[x].w);
					
					e[x].w = y;
				
			
			else 
				//printf("%d---\\n",T.que_c(x,y));
				printf("%d\\n",T.solve(x,y));
			
			
	return 0;


以上是关于P4949 最短距离(树剖)的主要内容,如果未能解决你的问题,请参考以下文章

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

[51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询

[51nod] 1766树上的最远点对 树的直径 树剖LCA+ST表静态查询

GLSL片段着色器-绘制简单的粗曲线

如何减少两行浏览片段之间的距离

树链剖分洛谷P3384树剖模板