zoukankan      html  css  js  c++  java
  • 【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

    题目描述

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

    $nle 3 imes 10^5$ ,$mle 5 imes 10^5$ 。


    题解

    树的直径+并查集+LCT

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

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

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

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

    #include <cstdio>
    #include <algorithm>
    #define N 300010
    using 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
    " , ans = max(dis(x , px[y]) , dis(x , py[y])) - 1);
    		if(!type) ans = 0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Angular入门到精通系列教程(3)
    Angular入门到精通系列教程(1)
    Angular入门到精通系列教程(2)
    嵌入在iframe中的Angular站点,如何打开一个新的tab页面
    简单实现无服务器情况下,2个GIT客户端的同步
    QP01 创建检验批计划
    IW31创建维修工单
    屏幕里输入字段值后的检查 SCREEN FIELD CHECK ON INPUT
    elasticsearch 基于文章点赞数计算评分
    script_score(帖子--根据 销量和浏览人数进行相关度提升)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8624085.html
Copyright © 2011-2022 走看看