【块状树】【LCA】bzoj1787 [Ahoi2008]Meet 紧急集合

分块LCA什么的,意外地快呢……

就是对询问的3个点两两求LCA,若其中两组LCA相等,则答案为第三者。

然后用深度减一减什么的就求出距离了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 using namespace std;
 5 #define maxn 500001
 6 struct Graph
 7 {int v[maxn<<1],first[maxn<<1],next[maxn<<1],w[maxn<<1],en;
 8 void AddEdge(const int &a,const int &b)
 9 {v[++en]=b;next[en]=first[a];first[a]=en;}}G;
10 int dep[maxn],fa[maxn],top[maxn],siz[maxn],x,y,z,sz,n,m;
11 int Abs(const int &x){return x<0 ? (-x) : x;}
12 int Res,Num;char C,CH[12];
13 inline int R()
14 {
15     Res=0;C=‘*‘;
16     while(C<‘0‘||C>‘9‘)C=getchar();
17     while(C>=‘0‘&&C<=‘9‘){Res=Res*10+(C-‘0‘);C=getchar();}
18     return Res;
19 }
20 inline void P(long long x)
21 {
22     Num=0;if(!x){putchar(‘0‘);return;}
23     while(x>0)CH[++Num]=x%10,x/=10;
24     while(Num)putchar(CH[Num--]+48);
25 }
26 void makeblock(int cur)
27 {
28     for(int i=G.first[cur];i;i=G.next[i])
29       if(G.v[i]!=fa[cur])
30         {
31           dep[G.v[i]]=dep[cur]+1;
32           fa[G.v[i]]=cur;
33           if(siz[top[cur]]<sz)
34             {
35               siz[top[cur]]++;
36               top[G.v[i]]=top[cur];
37             }
38           makeblock(G.v[i]);
39         }
40 }
41 inline int QLCA(int u,int v)
42 {
43     while(u!=v)
44       {
45         if(top[u]==top[v])
46           {
47             if(dep[u]<dep[v]) swap(u,v);
48             u=fa[u];
49           }
50         else
51           {
52             if(dep[top[u]]<dep[top[v]]) swap(u,v);
53             u=fa[top[u]];
54           }
55       }
56     return u;
57 }
58 int main()
59 {
60     n=R();m=R();
61     for(int i=1;i<n;i++)
62       {
63         x=R();y=R();
64         G.AddEdge(x,y);
65         G.AddEdge(y,x);
66       }
67     for(int i=1;i<=n;i++) {top[i]=i; siz[i]=1;}
68     sz=sqrt((double)n*5.0); makeblock(1);
69     for(;m>0;m--)
70       {
71         x=R();y=R();z=R();
72         int f1=QLCA(x,y),f2=QLCA(x,z),f3=QLCA(y,z);
73         if(f1==f2)
74           {
75             int f4=QLCA(x,f3); P(f3); putchar(‘ ‘);
76             P(Abs(dep[f3]-dep[y])+Abs(dep[f3]-dep[z])
77             +Abs(dep[f4]-dep[x])+Abs(dep[f4]-dep[f3])); puts("");
78           }
79         else if(f1==f3)
80           {
81             int f4=QLCA(y,f2); P(f2); putchar(‘ ‘);
82             P(Abs(dep[f2]-dep[x])+Abs(dep[f2]-dep[z])
83             +Abs(dep[f4]-dep[y])+Abs(dep[f4]-dep[f2])); puts("");
84           }
85         else
86           {
87             int f4=QLCA(z,f1); P(f1); putchar(‘ ‘);
88             P(Abs(dep[f1]-dep[x])+Abs(dep[f1]-dep[y])
89             +Abs(dep[f4]-dep[z])+Abs(dep[f4]-dep[f1])); puts("");
90           }
91       }
92     return 0;
93 }
时间: 2024-08-01 06:13:24

【块状树】【LCA】bzoj1787 [Ahoi2008]Meet 紧急集合的相关文章

[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,然后最小花费就是两两点之间的路径长度之和除以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

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

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

【BZOJ-1787】Meet紧急集合 倍增LCA

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 2259  Solved: 1023[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

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: [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 紧急集合(1832 [AHOI2008]聚会)

1787: [Ahoi2008]Meet 紧急集合 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 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

【Ahoi2008】【lca】【bzoj1787】Meet 紧急集合

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1787 题解: 求出三个点两两之间的lca会发现有两个是一样的,然后我们选那个不一样的就好了. #include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; struct use{ int st,en; }b[5000001]; in

【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] 到