博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT
阅读量:4317 次
发布时间:2019-06-06

本文共 2613 字,大约阅读时间需要 8 分钟。

给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林;询问一个点能到达的最远的点与该点的距离。强制在线。

$n\le 3\times 10^5$ ,$m\le 5\times 10^5$ 。


题解

树的直径+并查集+LCT

与直径相关的结论1:与一个点距离最大的点为任意一条直径的两个端点之一。

与直径相关的结论2:两棵树之间连一条边,新树直径的两个端点一定为第一棵树直径的两个端点和第二棵树直径的两个端点这四者中之二。

于是问题就变简单了,用并查集维护每个连通块的直径即可。由于强制在线,所以必须用LCT维护树上距离。

时间复杂度 $O(LCT·n\log n)=O(能过)$ 

#include 
#include
#define N 300010using namespace std;int f[N] , px[N] , py[N] , fa[N] , c[2][N] , si[N] , rev[N];int find(int x){ return x == f[x] ? x : f[x] = find(f[x]);}inline void pushup(int x){ si[x] = si[c[0][x]] + si[c[1][x]] + 1;}inline void pushdown(int x){ if(rev[x]) { swap(c[0][c[0][x]] , c[1][c[0][x]]) , rev[c[0][x]] ^= 1; swap(c[0][c[1][x]] , c[1][c[1][x]]) , rev[c[1][x]] ^= 1; rev[x] = 0; }}inline bool isroot(int x){ return x != c[0][fa[x]] && x != c[1][fa[x]];}void update(int x){ if(!isroot(x)) update(fa[x]); pushdown(x);}inline void rotate(int x){ int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1; if(!isroot(y)) c[c[1][z] == y][z] = x; fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y; pushup(y) , pushup(x);}inline void splay(int x){ int y , z; update(x); while(!isroot(x)) { y = fa[x] , z = fa[y]; if(!isroot(y)) { if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x); else rotate(y); } rotate(x); }}inline void access(int x){ int t = 0; while(x) splay(x) , c[1][x] = t , pushup(x) , t = x , x = fa[x];}inline void makeroot(int x){ access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] ^= 1;}inline int dis(int x , int y){ makeroot(x) , access(y) , splay(y); return si[y];}inline void link(int x , int y){ int tx = find(x) , ty = find(y) , mx = -1 , t , rx , ry; makeroot(x) , fa[x] = y; if(mx < (t = dis(px[tx] , py[tx]))) mx = t , rx = px[tx] , ry = py[tx]; if(mx < (t = dis(px[ty] , py[ty]))) mx = t , rx = px[ty] , ry = py[ty]; if(mx < (t = dis(px[tx] , px[ty]))) mx = t , rx = px[tx] , ry = px[ty]; if(mx < (t = dis(px[tx] , py[ty]))) mx = t , rx = px[tx] , ry = py[ty]; if(mx < (t = dis(py[tx] , px[ty]))) mx = t , rx = py[tx] , ry = px[ty]; if(mx < (t = dis(py[tx] , py[ty]))) mx = t , rx = py[tx] , ry = py[ty]; f[tx] = ty , px[ty] = rx , py[ty] = ry;}int main(){ int type , n , q , i , opt , x , y , ans = 0; scanf("%d%d%d" , &type , &n , &q); for(i = 1 ; i <= n ; i ++ ) f[i] = px[i] = py[i] = i , si[i] = 1; while(q -- ) { scanf("%d%d" , &opt , &x) , x ^= ans; if(opt == 1) scanf("%d" , &y) , y ^= ans , link(x , y); else y = find(x) , printf("%d\n" , ans = max(dis(x , px[y]) , dis(x , py[y])) - 1); if(!type) ans = 0; } return 0;}

 

转载于:https://www.cnblogs.com/GXZlegend/p/8624085.html

你可能感兴趣的文章
利用golang语法检查对象是否实现了接口
查看>>
在UBUNTU上安装基于bochs的 xv6
查看>>
Azure Storage Blob文件重命名
查看>>
RxJava2.0 使用
查看>>
FreeImage的图像处理软件
查看>>
ASP.NET MVC开发必看系列
查看>>
点到平面的距离
查看>>
linux下安装FTP
查看>>
第四周编程总结
查看>>
《第12章 类的无参方法》
查看>>
经典机器学习算法系列7-svd
查看>>
mxnet系列 全连接层代码阅读
查看>>
0715
查看>>
Android开发进度06
查看>>
Beautiful Soup 中文文档
查看>>
USB各种模式 解释
查看>>
数据访问-----ADO.NET 小结和练习
查看>>
Linux lsof详解
查看>>
子组件给父组件传数据
查看>>
unix/linux下的共享内存、信号量、队列信息管理
查看>>