CodeForces 593D Happy Tree Party
2016-01-27 21:41
295 查看
题目链接: http://codeforces.com/problemset/problem/593/D
---------------------------------------------------------------------------------------------------------------
刚看完题目感觉必须用树链剖分之类的方法,就放弃了,然而我们要发现题目具有如下性质:
一个$ long long $以内的数如果被大于$1$的数除 几十次就可以除到$0$了
所以就可以考虑下$LCA$
但如果长度为$1$的边过多 复杂度又不靠谱了 这时我们又会观察到修改时边的长度只减不增
因此对于长度为$1$的边 我们可以进行路径压缩
不过这里的压缩并不是改变原来的树的结构 因为改变树的结构就会麻烦许多
我们只需把以长度为$1$的边相连的点放在一个集合内, 如果集合内的一个点需要向上查找
就直接找到这个集合的顶端
$($尽管集合顶端的点并不一定是两点的$LCA $但由于集合内的边长均为$1$ 实际结果是等价的$)$
---------------------------------------------------------------------------------------------------------------
刚看完题目感觉必须用树链剖分之类的方法,就放弃了,然而我们要发现题目具有如下性质:
一个$ long long $以内的数如果被大于$1$的数除 几十次就可以除到$0$了
所以就可以考虑下$LCA$
但如果长度为$1$的边过多 复杂度又不靠谱了 这时我们又会观察到修改时边的长度只减不增
因此对于长度为$1$的边 我们可以进行路径压缩
不过这里的压缩并不是改变原来的树的结构 因为改变树的结构就会麻烦许多
我们只需把以长度为$1$的边相连的点放在一个集合内, 如果集合内的一个点需要向上查找
就直接找到这个集合的顶端
$($尽管集合顶端的点并不一定是两点的$LCA $但由于集合内的边长均为$1$ 实际结果是等价的$)$
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int N = 2e5 + 10; int firste , nexte[N << 1], v[N << 1]; long long w[N << 1]; int fa , d , aim , fa2 ; long long dist ; int n, m, e = 1; void build_edge(int x, int y, long long z) { nexte[++e] = firste[x]; firste[x] = e; v[e] = y; w[e] = z; } int findf(int x) { if(fa2[x] == x) return x; return fa2[x] = findf(fa2[x]); } void dfs(int u) { for(int p = firste[u]; p; p = nexte[p]) if(!fa[v[p]]) { aim[p / 2] = v[p]; fa[v[p]] = u; d[v[p]] = d[u] + 1; dist[v[p]] = w[p]; if(w[p] == 1) fa2[v[p]] = findf(u); dfs(v[p]); } } long long check(int x, int y, long long z) { while(x != y) { if(d[x] < d[y]) swap(x, y); if(dist[x] == 1) x = findf(x); else { z /= dist[x]; x = fa[x]; if(!z) return z; } } return z; } int main() { scanf("%d%d", &n, &m); int x, y; long long z; for(int i = 1; i < n; ++i) { scanf("%d%d%lld", &x, &y, &z); build_edge(x, y, z); build_edge(y, x, z); } fa[1] = 1; dist[1] = 1; for(int i = 1; i <= n; ++i) fa2[i] = i; dfs(1); while(m--) { scanf("%d", &x); if(x & 1) { scanf("%d%d%lld", &x, &y, &z); printf("%lld\n", check(x, y, z)); } else { scanf("%d%lld", &x, &z); int u = aim[x]; dist[u] = z; if(z == 1) fa2[u] = findf(fa[u]); } } return 0; }
相关文章推荐
- android sharedUserId 共享用户
- RNA-seq Data Analysis-A Practical Approach-book(2015) 笔记
- Android 关于屏幕的一些事儿
- cocos2dx 3.3 AssetsManager简单分析
- QQ SDK 分享实现,及不回调问题
- android150 笔记
- android中获取坐标
- 在Android Manifest中注册DownloadManager下载完成发送的广播
- ios中json解析出现的null问题
- Android获取数据过程中旋转屏幕问题
- xcode中添加pch全局引用文件
- Swift-类和结构体
- iOS图片上传
- 技术博客之路
- RemObjects SDK 9.0 Beta_CodeFirst
- flyme os 插桩红米2 教程
- iOS通过邮件获取APP异常崩溃信息
- App Widget详解
- Android之应用程序内存优化
- android内存泄露分析