loj 1412(树上最长直径的应用)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1412

思路:好久没写题解了,有点手生,这题从昨天晚上wa到现在终于是过了。。。思想其实很简单,就是预处理出每一块的最长直径,然后每次询问的时候直接查询就可以了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int MAXN = (100000 + 100);
 9 typedef pair<int,int>Pair;
10 
11 vector<int >g[MAXN];
12 vector<Pair >blocks;
13 int n,m,q,len,_count,max_len;
14 bool mark[MAXN];
15 
16 int dfs(int u,int father)
17 {
18     if(!mark[u])mark[u] = true, _count ++;
19     int first = 0, second = 0;
20     for(int i = 0; i < (int)g[u].size(); i ++) {
21         int v = g[u][i];
22         if(v == father)continue;
23         int tmp = dfs(g[u][i],u) + 1;
24         if(tmp > first)second = first, first = tmp;
25         else if(tmp > second)second = tmp;
26     }
27     if(first + second > len)len = first + second;
28     return first;
29 }
30 
31 int cmp(Pair p, Pair q)
32 {
33     if(p.second != q.second){
34         return p.second > q.second;
35     }else
36         return p.first > q.first;
37 }
38 
39 int main()
40 {
41     int u,v,_case,t=1;
42     scanf("%d",&_case);
43     while(_case--){
44         scanf("%d%d",&n,&m);
45         for(int i=0;i<=n;i++)g[i].clear();
46         while(m--){
47             scanf("%d%d",&u,&v);
48             g[u].push_back(v);
49             g[v].push_back(u);
50         }
51         len=0;
52         max_len = 0;
53         memset(mark,false,sizeof(mark));
54         blocks.clear();
55         for(int i=1;i<=n;i++){
56             if(!mark[i]){
57                 len=0;
58                 _count = 0;
59                 dfs(i,-1);
60                 blocks.push_back(make_pair(len,_count));
61                 max_len = max(max_len,len);
62             }
63         }
64         sort(blocks.begin(),blocks.end(),cmp);
65         scanf("%d",&q);
66         printf("Case %d:\n",t++);
67         while(q--){
68             int k;
69             scanf("%d",&k);
70             if(k > blocks[0].second){
71                 puts("impossible");
72             }else if(k <= max_len + 1){
73                 printf("%d\n",k - 1);
74             }else {
75                 int ans = (1 << 30);
76                 for(int i=0; i<(int)blocks.size(); i++){
77                     if(k > blocks[i].second)break;
78                     ans = min (ans, (blocks[i].first)+2*(k-blocks[i].first-1));
79                 }
80                 printf("%d\n",ans);
81             }
82         }
83                             
84     }
85     return 0;
86 }
87 
88 
89                 
90 
91         
92             
93 
94 
95         
96 
97         
View Code

 

转载于:https://www.cnblogs.com/wally/p/3465705.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值