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

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

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

loj 1412(树上最长直径的应用)
 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

 

你可能感兴趣的:(应用)