51 nod 1427 文明 (并查集 + 树的直径)
1427 文明
题目来源: CodeForces
安德鲁在玩一个叫“文明”的游戏。大妈正在帮助他。
这个游戏里面有n个城市和m条双向的道路。城市从1到n编号。对于每一对城市,他们之间要么有唯一的一条道路,要么就是不可互达。一条道路的定义是一个包含不同城市的序列 v1, v2,...,vk , vi 和 vi+1 (1≤ i < k)之间有直接的一条道路相连。这条道路的长度是k-1。两个城市在同一区域的条件是当且仅当他们之间可以互达。
在游戏过程中,会有两个事件。
1. 安德鲁问大妈,城市x所在的区域里面最长的道路是多长。
2. 安德鲁要求大妈,合并城市x和城市y所在的区域。如果这两个城市本来在同一个区域,那么就不用合并。否则合并两个区域:从城市x所在区域选一个城市,再从城市y所在区域选一个城市,然后给这两个城市连一条边。选择这两个城市的时候要使得合并之后的区域里面最长道路尽可能小。如果有多种方案,任选一种即可。
大妈发现这些问题好难哦,所以他想请你来帮助一下。
单组测试数据。
第一行包含三个整数n,m,q(1 ≤ n ≤ 3*10^5; 0 ≤ m < n; 1 ≤ q ≤ 3*10^5),分别表示城市数目,道路数目,查询数目。
接下来m行,每行有两个整数 ai 和bi (ai ≠ bi; 1 ≤ ai, bi ≤ n)。表示ai和bi之间有一条直接相连的道路。两个城市之间最多有一条直接相连的道路。
接下来q行的格式是下列之一:
1 xi 。(1 ≤ xi ≤ n)。这种情况要查询当前xi所在的区域的最长道路。
2 xi yi。 (1 ≤ xi, yi ≤ n)。这种情况下要求合并xi和yi所在的区域。注意:xi和yi可能是一样的。
对于第1类查询,输出当前区域的最长路径长度。
6 0 7
2 1 2
2 3 4
2 5 6
2 3 2
2 5 3
1 1
1 1
4
4
/*
51 nod 1427 文明 (并查集 + 树的直径) problem:
给你n个城市,m条双向边连接,然后是q个查询
1 x: 城市x所在的区域的最长道路
2 x y:将两个城市的所在区域连接,要求维护最长路最短. solve:
一个区域的最长路就相当于树的直径.因为两个城市之间最多只有一条路径.
合并的话,如果要求最短,那么相当于将两条直径的中点相连. 所以已知A,B的直径可计算出新的直径的值
(注意还要与A,B的直径进行下比较).
先处理出每个区域的树的直径.然后可给每个区域打上标记,用并查集合并维护一下区域的树的直径. hhh-2016/09/27-17:21:09
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <math.h>
#define lson i<<1
#define rson i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define key_val ch[ch[root][1]][0]
using namespace std;
const int maxn = 3e5 + 100;
const int inf = 0x3f3f3f3f;
const ll mod = 1000000007;
const double eps = 1e-7;
template<class T> void read(T&num)
{
char CH;
bool F=false;
for(CH=getchar(); CH<'0'||CH>'9'; F= CH=='-',CH=getchar());
for(num=0; CH>='0'&&CH<='9'; num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p)
{
if(!p)
{
puts("0");
return;
}
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
} struct node
{
int v,next;
} edge[maxn << 1];
ll Max;
int tot,pos;
int head[maxn];
int vis[maxn];
//int ans[i];
int pre[maxn];
struct Node
{
ll dis;
int pre;
} pnode[maxn];
void init(int n)
{
memset(head,-1,sizeof(head));
tot = 0;
for(int i = 1; i <= n; i++)
{
vis[i] = 0;
pnode[i].pre = i;
pnode[i].dis = 1;
}
}
void add_edge(int u,int v)
{
edge[tot].v = v,edge[tot].next = head[u],head[u] = tot ++;
} void dfs(int u,int fa,ll len,int anc)
{
vis[u] = 1;
pnode[u].pre = anc;
if(len > Max)
{
Max = len;
pos = u;
} for(int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].v;
if(v == fa)
continue;
dfs(v,u,len + 1LL,anc);
}
} void cal(int now)
{
int from;
pos = 0,Max =0 ;
dfs(now,-1,0,now);
from = pos;
pos = 0,Max = 0;
dfs(from,-1,0,now);
pnode[now].dis = Max;
} int fin(int u)
{
if(pnode[u].pre != u)
return pnode[u].pre = fin(pnode[u].pre);
return u;
} void unio(int u,int v)
{
int ta = fin(u);
int tb = fin(v); if(ta == tb)
return ;
if(ta > tb)
swap(ta,tb);
pnode[ta].pre =tb;
ll tMax = 0;
tMax = max(pnode[ta].dis,pnode[tb].dis);
tMax = max(tMax,(pnode[ta].dis+1LL)/2LL+(pnode[tb].dis + 1LL)/2LL + 1LL);
pnode[tb].dis = tMax;
pnode[ta].dis= tMax;
} int main()
{
int n,m,q;
int u,v,ob;
read(n),read(m),read(q);
init(n);
for(int i = 1; i <= m; i++)
{
read(u),read(v);
add_edge(u,v);
add_edge(v,u);
}
for(int i = 1;i <= n;i++)
{
if(!vis[i])
cal(i);
}
for(int i = 1; i <= q; i++)
{
read(ob);
if(ob == 1)
{
read(u);
int ta = fin(u);
print(pnode[ta].dis);
}
else
{
read(u),read(v);
unio(u,v);
}
}
return 0;
}
51 nod 1427 文明 (并查集 + 树的直径)的更多相关文章
- 51 nod 1515 明辨是非(并查集合并)
1515 明辨是非题目来源: 原创基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以 ...
- 【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树的直径/LCA/树的点分治
题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F ...
- CodeForces 455C Civilization (并查集+树的直径)
Civilization 题目链接: http://acm.hust.edu.cn/vjudge/contest/121334#problem/B Description Andrew plays a ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- BZOJ-3211花神游历各国 并查集+树状数组
一开始想写线段树区间开方,简单暴力下,但觉得变成复杂度稍高,懒惰了,编了个复杂度简单的 3211: 花神游历各国 Time Limit: 5 Sec Memory Limit: 128 MB Subm ...
- BZOJ3211 花神游历各国 并查集 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3211 题意概括 有n个数形成一个序列. m次操作. 有两种,分别是: 1. 区间开根(取整) 2. ...
- hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点)
hdu 6200 mustedge mustedge(并查集+树状数组 或者 LCT 缩点) 题意: 给一张无向连通图,有两种操作 1 u v 加一条边(u,v) 2 u v 计算u到v路径上桥的个数 ...
- 【bzoj4869】[Shoi2017]相逢是问候 扩展欧拉定理+并查集+树状数组
题目描述 Informatik verbindet dich und mich. 信息将你我连结. B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以分为两种:0 ...
- 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)
题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...
随机推荐
- github上传时出现error: src refspec master does not match any解决办法
github上传时出现error: src refspec master does not match any解决办法 这个问题,我之前也遇到过,这次又遇到了只是时间间隔比较长了,为了防止以后再遇到类 ...
- Android实验报告
实验名称:Android程序设计 实验时间:2017.5.24 实验人员:20162309邢天岳(结对同学20162313苑洪铭) 实验目的:使用android stuidio开发工具进行基本安卓软件 ...
- Hibernate之ORM与Hibernate
ORM: ORM是 Object /Relation Mapping,对象/关系数据库映射. 目前比较流行的编程语言,如java ,c#等,它们都是面向对象的编程语言,而目前比较主流的数据库产品,如O ...
- JAVA_SE基础——19.数组的定义
数组是一组相关数据的集合,数组按照使用可以分为一维数组.二维数组.多维数组 本章先讲一维数组 不同点: 不使用数组定义100个整形变量:int1,int2,int3;;;;;; 使用数组定义 int ...
- python 中 reduce 函数的使用
reduce()函数也是Python内置的一个高阶函数. reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接 ...
- 新概念英语(1-139)Is that you, John?
Lesson 139 Is that you, John? 是你吗,约翰? Listen to the tape then answer this question. Which John Smith ...
- shuffle和sort分析
MapReduce中的Shuffle和Sort分析 MapReduce 是现今一个非常流行的分布式计算框架,它被设计用于并行计算海量数据.第一个提出该技术框架的是Google 公司,而Google 的 ...
- ssm框架找不到mysql驱动类WARN DriverManagerDataSource:107 - Could not load driverClass com.mysql.jdbc.Driver
找了很久错误,检查了配置文件,和spring配置数据源,都没有发现问题,最后上网查询了下,发现是由于配置文件后面有空格. 去除掉配置文件后面的空格就可以正常运行了.
- [POI2008]BLO-Blockade - Tarjan,割点
Description 给定一张无向图,求每个点被封锁(删去与其相连的边)之后有多少个有序点对(x,y)(x!=y,1<=x,y<=n)满足x无法到达y. Input&Output ...
- Android学习——移植tr069程序到Android平台
原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...