CodeForces 593D Happy Tree Party [LCA+并查集]

题意:给一棵树,每条边有一个权值,给两种操作,第一种是询问y向下整除从a到b的最短路径中每条边的权值后y的值,第二种是改变某条边的权值。

思路:y的最大值为1e18,最多除大于等于2的数不超过60次即可将y变为0,先dfs以任意一点为根建树,记录每个点的深度和它的父结点并将边权转化为点权,

再搞个并查集,将权值为1的点压缩,即使pre[u]=g[u];(u变成u的爸爸)。

 1 #include<bits/stdc++.h>
 2 #define fi first
 3 #define se second
 4 using namespace std;
 5 typedef long long ll;
 6 const int inf=1e9;
 7 const double PI=acos(-1);
 8 const double eps=1e-6;
 9 const int mod=1e9+7;
10 const int maxn=2e5+10;
11 int n,m;
12 typedef pair<int,int> pii;
13 vector<pii>f[maxn];
14 ll val[maxn];
15 int pos[maxn],pre[maxn],dep[maxn],g[maxn];
16 int find(int k){
17     if(k==pre[k]) return k;
18     return pre[k]=find(pre[k]);//并查集
19 }
20 void dfs(int u,int fa){
21     g[u]=fa;//u的爸爸
22     for(pii x:f[u]){
23         if(x.fi==fa) continue;
24         pos[x.fi]=x.se;//记录每个点对应的边权的编号,边权转点权
25         dep[x.fi]=dep[u]+1;//计算深度
26         dfs(x.fi,u);
27     }
28 }
29 void up(int u){
30     pre[u]=g[u];//u变成u的爸爸
31 }
32 ll lca(int a,int b,ll y){
33     a=find(a),b=find(b);
34     while(a!=b){
35         if(dep[a]<dep[b]) swap(a,b);//每次将较深的点向上找
36         if(val[pos[a]]==1) up(a);//点权为1时,压缩该点
37         y/=val[pos[a]];a=find(g[a]);//除以该点的权值
38         if(y==0) return 0;//y为0直接跳出
39     }
40     return y;
41 }
42 int main(){
43     ios::sync_with_stdio(false);
44     //freopen("in","r",stdin);
45     cin>>n>>m;
46     for(int i=0;i<=n;i++) pre[i]=i;
47     for(int i=1,u,v;i<n;i++){
48         cin>>u>>v>>val[i];
49         f[u].push_back(pii(v,i));
50         f[v].push_back(pii(u,i));
51     }
52     dfs(1,0);
53     for(int i=1;i<=m;i++){
54         int op,a,b,p;
55         ll c,y;
56         cin>>op;
57         if(op==1){
58             cin>>a>>b>>y;
59             cout<<lca(a,b,y)<<endl;
60         }else{
61             cin>>p>>c;
62             val[p]=c;
63         }
64     }
65     return 0;
66 }

  

原文地址:https://www.cnblogs.com/xyq0220/p/10673205.html

时间: 2024-11-09 18:44:53

CodeForces 593D Happy Tree Party [LCA+并查集]的相关文章

【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

[题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1<=wi<=10^9. [算法]最小生成树+倍增LCA+并查集 [题解]首先求出图的一个最小生成树,则所有边分成树边和非树边. 对于非树边(u,v),假设u和v在最小生成树上的路径的最大边权Max,那么一定满足w(u,v)<=Max /////////////////////////////////////// 原文地址:https://ww

CodeForces 776D The Door Problem【并查集】

CodeForces 776D The Door Problem[并查集]并查集 设 f 1--m 表示 开的情况 m+1--2*m 表示关的情况 对于每盏灯 如果他 是关的 则 x--y x+m--y+m 表示要同关 或者同开 如果他 是开的 则 x+m--y x--y+m 表示一个关 一个开如果一盏灯 的 x 连向 了 x+m 则表示是矛盾了 那么久是错误的 题意:给你n个门,和m组开关,每扇门都有两个开关控制,每个开关控制x扇门,如果选择了某组开关,则使这组开关里的每个开关控制的所有的门按

Codeforces Round #250 (Div. 1) B 并查集

坑!神坑!深坑!,WA了几十把,最终答案  (ans * 2)/(n * 1.0 * (n - 1)) 要是写成(ans * 2)/(n *(n - 1)*1.0)就是WA,不明白为啥,愤怒的我 全改成double就可以了,若前面变量用了int的 答案必须是前一种写法, 题目不是特别难,没啥思路画一画就有思路了,10^5的n去扫肯定是要超时的,那就想想一次性的10^5,发想通过m是可以的,建边,边权就是两端点中小的那个,然后对最终答案的种数进行分析,发现其实就是 每次你要连接的两块连通块的个数相

From Tree to Graph lca 并查集

题意: 给定一棵树 当前树的答案为 $f[1]^f[2]^f[3]^..^f[n]$     f[i]表示去除掉i点 该树的联通块数量 有m次操作  每次将两个点连一条边   然后再输出该树的答案 题目 题解: 显然一开始的时候  答案为每个点的答案为其度  所以可以处理好一开始的答案 如果将两个点连在一起的时候  那么该路径所经过的点(不包括这两个端点) 的答案都会减一 但是考虑到有时候会重复更新   可以将每个点转移到他到儿子的边上  显然 他有多少个儿子就可以被减多少次答案   正好匹配上

Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

题目链接: Hdu 5458 Stability 题目描述: 给出一个还有环和重边的图G,对图G有两种操作: 1 u v, 删除u与v之间的一天边 (保证这个边一定存在) 2 u v, 查询u到v的路径上有几条桥. 解题思路: 这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点.如果按照顺序来,删边时候求桥就是问题了.所以可以离线处理,然后一边记录答案一边加边缩点. 对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目.查询的时候对于(u, v)

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

BZOJ 3910 火车 LCA+并查集

题目大意 给出一棵树,起点,和要经过的点的序列,已经经过的点就不用去了,剩下的点按照顺序依次去,问要经过多少条边. 思路 链剖大概应该是可以,不过没试,用了听大爷说的一种神奇的方法. 因为树上经过的点肯定是一段一段的,就想到用并查集将一段合成一个点,每个点最多只能被合一次,这样的话就能保证时间复杂度.查询的时候像链剖一样一段一段往上跳就行了,还要顺便把路径上的所有点缩起来. CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #incl

【BZOJ-3910】火车 倍增LCA + 并查集

3910: 火车 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 262  Solved: 90[Submit][Status][Discuss] Description A 国有n 个城市,城市之间有一些双向道路相连,并且城市两两之间有唯一路径.现在有火车在城市 a,需要经过m 个城市.火车按照以下规则行驶:每次行驶到还没有经过的城市中在 m 个城市中最靠前的.现在小 A 想知道火车经过这m 个城市后所经过的道路数量. Input 第一行三个整数

【BZOJ3910】火车 LCA+并查集

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44780959"); } 题解: 首先找两点之间路径可以用倍增LCA. 然后标记哪个点走过可以用并查集,均摊下来最后是线性的. 代码: #include <cstdio> #include <cstring>