TZOJ 4651 zry和他的的灯泡们(lca)

描述

zry有一个收集灯泡的习惯,他把灯泡的阴极都共地,阳极连成一颗树,这样的话,他只要在任意一个灯泡的阳极加上合适的电压,所有灯泡都能亮起来。不幸的是,有一对灯泡之间的阳极连线断掉了,这样的话,这颗灯泡树就还有一部分能亮,一部分不能亮了。zry想知道如果他在任意一个灯泡的阳极上加电压,这一对灯泡的哪一个会亮?

输入

首先是一个正整数T(1<=T<=10)表示测试数据的组数。
对于每一组测试数据:
第一行是一个整数n,q(3<=n,q<=100000),n表示灯泡总数,q表示查询个数。
接下来的n-1行,每行2个整数x,y(1<=x,y<=n),表示灯泡x和灯泡y的阳极相连。(数据保证合法,是一棵树)
接下来的q行,每行3个整数,a,b,c(1<=a,b,c<=n,数据保证合法,灯泡a和灯泡b之间有边且a不等于b)表示灯泡a和灯泡b之间阳极连线断开的话,在c的阳极加一个电压。

输出

每个查询之间相互独立,对于每个查询输出a和b哪一个会亮,输出a或者b即可。

样例输入

1
3 1
1 2
2 3
1 2 3

样例输出

2

题意

给一棵树,每次询问断掉一条边(a,b),问c和a还是b连通。

题解

不妨这么想,如果删了(a,b),那么c和两个点的距离哪个近就输出哪个。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N=1e5+5,L=18;
 5 int dep[N],fa[N][L],lg[N],n;
 6 bool vis[N];
 7 vector<int>G[N];
 8 void dfs(int u)
 9 {
10     vis[u]=1;
11     for(int i=0;i<G[u].size();i++)
12     {
13         int v=G[u][i];
14         if(vis[v])continue;
15         fa[v][0]=u;
16         dep[v]=dep[u]+1;
17         dfs(v);
18     }   
19 }
20 void RMQ()
21 {
22     for(int j=1;(1<<j)<=n;j++)
23         for(int i=1;i<=n;i++)
24             fa[i][j]=fa[fa[i][j-1]][j-1];
25 }
26 int lca(int x,int y)
27 {
28     if(dep[x]<dep[y])swap(x,y);
29     while(dep[x]>dep[y])x=fa[x][lg[dep[x]-dep[y]]-1];
30     if(x==y)return x;
31     for(int k=lg[dep[x]];k>=0;k--)
32         if(fa[x][k]!=fa[y][k])
33             x=fa[x][k],y=fa[y][k];
34     return fa[x][0];
35 }
36 int dist(int u,int v){return dep[u]+dep[v]-2*dep[lca(u, v)];}
37 int main()
38 {
39     for(int i=1;i<N;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
40     int t;
41     scanf("%d",&t);
42     while(t--)
43     {
44         int q;
45         scanf("%d%d",&n,&q);
46         for(int i=1;i<=n;i++)vis[i]=0;
47         for(int i=1;i<=n;i++)G[i].clear();
48         for(int i=1,u,v;i<n;i++)
49         {
50             scanf("%d%d",&u,&v);
51             G[u].push_back(v);
52             G[v].push_back(u);
53         }
54         dfs(1);
55         RMQ();
56         while(q--)
57         {
58             int a,b,c;
59             scanf("%d%d%d",&a,&b,&c);
60             int dis1=dist(a,c),dis2=dist(b,c);
61             if(dis1<dis2)printf("%d\n",a);
62             else printf("%d\n",b);
63         }
64     }
65     return 0;
66 }
上一篇:最长公共子序列(LCS)tzoj:5752


下一篇:lsyncd + rsync 分布式代码分发与老系统图片上七牛云