关闭

LCA + 并查集 Happy Tree Party codeforces593D

标签: LCA并查集
212人阅读 评论(0) 收藏 举报
分类:

一个64位的数,最多在被大于1的数整除64次后就变为0

所以对于每次访问,我们最多除64次

那么我们就要将为1的路压缩,使用并查集

每次访问使用lca,找到公共祖先lc,然后u->lc,v->lc,访问这两条路

记得并查集的时候要用

return par[u] == u ? u : par[u] = find(par[u]);

不要用

return par[u] == u ? u :  find(par[u]);

后者也能查询,但是前者再并在一起省时,不然会t的

/********************************************
Author         :Crystal
Created Time   :
File Name      :
********************************************/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
#define MEM(a,b) memset(a,b,sizeof a)
#define CLR(a) memset(a,0,sizeof a);
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
//#define LOCAL
#define maxn 500005
int root = 1;
int head[maxn],nxt[maxn],pnt[maxn];
int par[maxn];
ll cost[maxn];
int dep[maxn],far[maxn],p[maxn][30];
ll path[maxn][30];
int dis[maxn];
int u[maxn];
int v[maxn];
ll c[maxn];
int cnt = 0;
int n,q;
int find(int u){
	return par[u] == u ? u : par[u] = find(par[u]);
}
void addedge(int u,int v,ll c){
	pnt[cnt] = v;
	nxt[cnt] = head[u];
	cost[cnt] = c;
	head[u] = cnt++;
}
int llog = 20;
void dfs(int u,int f,int d){
	dep[u] = d;
	p[u][0] = f;
	for(int i=head[u];~i;i = nxt[i]){
		int v = pnt[i];
		if(v == f)continue;
		path[v][0] = cost[i];
		dfs(v, u, d+1); 
	}
}
void init(){
	dfs(root, -1, 0);
	for(int i=0;i+1<llog;i++){
		for(int v=1;v<=n;v++){
			if(p[v][i] == -1)p[v][i+1] = -1;
			else p[v][i+1] = p[p[v][i]][i];
		}
	}
}
int lca(int u,int v){
	if(dep[u] > dep[v])swap(u,v);
	for(int i=0;i<llog;i++){
		if(dep[v]-dep[u] >> i & 1){
			v = p[v][i];
		}
	}
	if(u == v)return u;
	for(int i=llog - 1;i != -1;i--){
		if(p[u][i] != p[v][i]){
			u = p[u][i];
			v = p[v][i];
		}
	}
	return p[u][0];
}
ll solve(int u,int v,ll x){
	//cout << u <<v <<x << endl;
	int cnt = 0;
	while(x && dep[u] < dep[v] && cnt < 65){
		v = find(v);
		if(dep[u] >= dep[v])break;
		x /= path[v][0];
		v = p[v][0];
		cnt++;
	}
	return x;
}
int main()
{
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
//	freopen("out.txt","w",stdout);
#endif
	cin >> n >> q;
	MEM(head,-1);
	for(int i=1;i<n;i++){
		scanf("%d%d%lld",&u[i],&v[i],&c[i]);
		addedge(u[i],v[i],c[i]);
		addedge(v[i],u[i],c[i]);
	}
	for(int i=1;i<=n;i++)par[i] = i;
	init();
	for(int i=1;i<n;i++){
		if(c[i]==1){
			if(dep[u[i]] > dep[v[i]]){
				par[u[i]] = find(v[i]);
			}
			else{
				par[v[i]] = find(u[i]);
			}
		}
	}
	for(int i=1;i<=q;i++){
		int f;cin >> f;
		if(f==1){
			int u,v;
			ll x;
			scanf("%d%d%lld",&u,&v,&x);
			int lc = lca(u,v);
			//cout << lc  << endl;
			x = solve(lc,u,x);
			x = solve(lc,v,x);
			printf("%lld\n",x);
		}
		else{
			int load;
			ll x;scanf("%d%lld",&load,&x);
			int a = u[load];
			int b = v[load];
			if(dep[a]>dep[b]){
				path[a][0] = x;
			}
			else{
				path[b][0] = x;
			}
			if(x == 1){
				if(dep[a]>dep[b]){
					par[a] = find(b);
				}
				else par[b] = find(a);
			}
		}
	}
	return 0;
}





0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:16959次
    • 积分:886
    • 等级:
    • 排名:千里之外
    • 原创:75篇
    • 转载:1篇
    • 译文:0篇
    • 评论:1条
    最新评论