bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)

1787: [Ahoi2008]Meet 紧急集合

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 1841  Solved: 857
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

6 4
1 2
2 3
2 4
4 5
5 6
4 5 6
6 3 1
2 4 4
6 6 6

Sample Output

5 2
2 5
4 1
6 0

HINT

Source

Day1

【思路】

Lca。

求出三点之间的lca,会出现两个点相同的情况,集合点为另外一个点。

【代码】

 1 /**************************************************************
 2     Problem: 1787
 3     User: hahalidaxin2
 4     Language: C++
 5     Result: Accepted
 6     Time:3716 ms
 7     Memory:65216 kb
 8 ****************************************************************/
 9
10 #include<cstdio>
11 #include<cstring>
12 #include<queue>
13 #include<vector>
14 #include<iostream>
15 using namespace std;
16
17 const int maxn = 500000+10;
18 const int maxd = 19;
19
20 struct Edge{ int u,v;
21 };
22 vector<int> G[maxn];
23 vector<Edge> es;
24
25 int d[maxn];
26 int p[maxn][maxd];
27
28 void addedge(int u,int v) {
29     es.push_back((Edge){u,v});
30     int m=es.size(); G[u].push_back(m-1);
31 }
32 void dfs(int u,int fa) {
33     for(int i=1;i<=maxd;i++) {       //构造倍增数组
34         if(d[u]<(1<<i)) break;
35         p[u][i]=p[p[u][i-1]][i-1];
36     }
37     for(int i=0;i<G[u].size();i++) {
38         Edge e=es[G[u][i]]; int v=e.v;
39         if(v!=fa)
40             d[v]=d[u]+1 , p[v][0]=u , dfs(v,u);
41     }
42 }
43 int lca(int u,int v) {
44     if(d[v]>d[u]) swap(u,v);
45     int dep=d[u]-d[v];
46     for(int i=0;i<maxd;i++)
47         if((1<<i)&dep) u=p[u][i];
48     if(u==v) return u;
49     for(int i=maxd-1;i>=0;i--)
50         if(p[u][i]!=p[v][i])
51             u=p[u][i] , v=p[v][i];
52     return p[u][0];
53 }
54 int dist(int x,int y) { return d[x]+d[y]-(d[lca(x,y)]<<1); }
55 int n,m;
56
57 void read(int& x) {
58     char c=getchar();
59     while(!isdigit(c)) c=getchar();
60     x=0;
61     while(isdigit(c))
62         x=x*10+c-‘0‘ , c=getchar();
63 }
64 int main() {
65     read(n),read(m);
66     int u,v;
67     for(int i=0;i<n-1;i++) {
68         read(u),read(v);
69         addedge(u,v); addedge(v,u);
70     }
71     dfs(n>>1,-1);
72     int a,b,c,lab,lac,lbc,s;
73     while(m--) {
74         read(a),read(b),read(c);
75         lab=lca(a,b),lac=lca(a,c),lbc=lca(b,c);
76         if(lab==lac) s=lbc;
77         else if(lab==lbc) s=lac;
78         else s=lab;
79         printf("%d %d\n",s,dist(a,s)+dist(b,s)+dist(c,s));
80     }
81     return 0;
82 }
时间: 2024-10-28 09:52:01

bzoj 1787 [Ahoi2008]Meet 紧急集合(1832 [AHOI2008]聚会)的相关文章

bzoj 1787: [Ahoi2008]Meet 紧急集合

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3016  Solved: 1344[Submit][Status][Discuss] Description Input Output Sample Input 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 Sample Output 5 2 2 5 4 1 6 0 HINT Source Day1

BZOJ 1787: [Ahoi2008]Meet 紧急集合( 树链剖分 )

这道题用 LCA 就可以水过去 , 但是我太弱了 QAQ 倍增写LCA总是写残...于是就写了树链剖分... 其实也不难写 , 线段树也不用用到 , 自己YY一下然后搞一搞就过了...速度还挺快的好像= = #9 ---------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algori

1787: [Ahoi2008]Meet 紧急集合

1787: [Ahoi2008]Meet 紧急集合 Description Input Output Sample Input 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 Sample Output 5 2 2 5 4 1 6 0 HINT 题解: n-1条边,很明显这是一棵树 那么题目就是求3个点的LCA 我们将3个点x,y,z分别求出x,y的LCA,设为a,x,z的为b,y,z的为c 则a,b,c 3个点中必有两个相等,答案就是另外一个(自

bzoj 1787 &amp;&amp; bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通过这些道路可以走遍Y岛的所有城市. 神奇的是,乘车经过每条道路所需要的费用都是一样的. 小可可,小卡卡和小YY经常想聚会,每次聚会,他们都会选择一个城市,使得3个人到达这个城市的总费用最小. 由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成. 他们

BZOJ——1787: [Ahoi2008]Meet 紧急集合

http://www.lydsy.com/JudgeOnline/problem.php?id=1787 题目描述 输入 输出 样例输入 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 样例输出 5 2 2 5 4 1 6 0 提示 易发现:三个点两两求出LCA,一定至少有两个LCA相等 若只有两个相等,那聚集点就是剩下的LCA 若三个相等,那聚集点就是LCA 1 #include <algorithm> 2 #include <cstdi

【bzoj1787】[Ahoi2008]Meet 紧急集合

求三个结点到一个结点距离之和最小的结点以及距离和 求出两两lca,其中有两个相同,答案则为另一个 感觉就是一大暴力... 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<queue> 8 using namesp

BZOJ1787 [Ahoi2008]Meet 紧急集合

水题 求出三个人每两个间的LCA,然后最小花费就是两两点之间的路径长度之和除以2 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 500005; 6 struct edge{ 7 int v,next; 8 }e[maxn*2]; 9 struct ask{ 10 int v,next,lca,d,u; 11

[bzoj1787][Ahoi2008]Meet 紧急集合(lca)

传送门 可以看出,三个点两两之间的lca会有一对相同,而另一个lca就是聚集点. 然后搞搞就可以求出距离了. ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define MAXN 1000001 5 6 using namespace std; 7 8 int n, m, cnt, ans; 9 int head[MAXN], to[MAXN], next[MAXN], de

【bzoj1787】[Ahoi2008]Meet 紧急集合 倍增LCA

题目描述 输入 输出 样例输入 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 样例输出 5 2 2 5 4 1 6 0 题解 倍增LCA 首先有集合点必定在三点中两个点的LCA处,大概画一下就看出来了. 然后有x到y的距离为deep[x]+deep[y]-2*deep[lcaxy] 那么x.y.z三点到lcaxy的距离为deep[x]+deep[y]-2*deep[lcaxy]+deep[lcaxy]+deep[x]-deep[lcaxyz] 到