UVALive 6712(2013长春区域赛)

Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that
there are N nodes and (N −1) edges that connect all the nodes. Each country has a base station located
in one node. All three countries will not place their station in the same node. And each country will
start from its base station to occupy other nodes. For each node, country A will occupy it iff other two
country’s base stations have larger distances to that node compared to country A. Note that each edge
is of the same length.
Given three country’s base station, you task is to calculate the number of nodes each country
occupies (the base station is counted).
Input
The input starts with a single integer T (1 ≤ T ≤ 10), the number of test cases.
Each test cases starts with a single integer N (3 ≤ N ≤ 105
), which means there are N nodes in
the tree.
Then N − 1 lines follow, each containing two integers u and v (1 ≤ u, v ≤ N, u ̸= v), which means
that there is an edge between node u and node v.
Then a single integer M (1 ≤ M ≤ 105
) follows, indicating the number of queries.
Each the next M lines contains a query of three integers a, b, c (1 ≤ a, b, c ≤ N, a, b, c are distinct),
which indicates the base stations of the three countries respectively.
Output
For each query, you should output three integers in a single line, separated by white spaces, indicating
the number of nodes that each country occupies. Note that the order is the same as the country’s base
station input.
Sample Input
1
9
1 2
1 3
1 4
2 5
2 6
2 7
6 8
6 9
2
1 2 8
2 1 4
Sample Output
3 3 1

6 2 1


 第一次写解题报告,希望大家能够喜欢。

      废话不多说,直接进入正题。

      题意:就是给定一颗有n个结点的树,有n-1条边,然后给出m次询问,每次询问给出三个点,对于每个点输出在这颗树上有多少个点到该点的距离小于分别到其它两点的距离(等于不算)。

     我想只要不是初学者一定不会去想用暴力法求解吧O(m*n)最大可到达100亿,显然不会去这样写。

     参考解法:因为是一棵树,先考虑两个点,对于树上任意两点间的最短路径是唯一的,找出路径的中点当然中点也可以是一条边,这样就可以以中点将树一分为二,这样对于这两个点的可行解自然就落在了自己所在这部分树的所有节点,那么怎样快速找到中点的,可以先用LCA(倍增法)将树预处理,对于两点u和v,找出它们的LCA,假设u的深度>=v的深度,则路径中点为距离u为dist[u][v]/2的祖先,这步可在O(logn)完成,由于是三个点,对于每个点可以先求出与其它两点的解,然后取交集就是答案,这步可以借助树的DFS序列O(1)完成。


#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         using namespace std; #define maxn 100100 int n,d; int fa[maxn][20]; int head[maxn]; int next[maxn<<1]; int edge[maxn<<1]; int pre[maxn]; int nn; int l[maxn]; int r[maxn]; int stop; int ll1[2][maxn]; int rr1[2][maxn]; int vis[2][maxn]; void add(int u,int v) { edge[d]=v; next[d]=head[u]; head[u]=d++; } void dfs(int u,int cent) { stop++; l[u]=stop; pre[u]=cent; int i; for(i=head[u];i!=-1;i=next[i])if(!pre[edge[i]]){ fa[edge[i]][0]=u; dfs(edge[i],cent+1); } r[u]=stop; } void init() { int i,j; for(j=1;(1< 
        
          <=n;j++) for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; } void Swap(int &u,int &v) { int temp=u; u=v; v=temp; } int lca(int u,int v) { if(pre[u] 
         
           =0;i--) if(fa[u][i]!=fa[v][i]){ u=fa[u][i]; v=fa[v][i]; } return fa[u][0]; } void solve(int u,int v1,int v,int v2) { int i; int f=lca(u,v); if(pre[u] 
          
            >=1; int zhong=u; for(i=0;(1< 
           
             <=ll;i++)if((1< 
             
            
           
          
         
       
      
      
     
     
    
    
   
   

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值