loj 1412(ツリー上の最長直径の応用)

13861 ワード

タイトルリンク:http://lightoj.com/volume_showproblem.php?problem=1412
構想:久しぶりに問題解を書いて、ちょっと手慣れて、この問題は昨日の夜からwaが今までやっと過ぎました...考えは実は簡単で、1枚1枚の最長直径を前処理して、それから尋ねるたびに直接調べることができます.
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:
",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
",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
",ans); 81 } 82 } 83 84 } 85 return 0; 86 } 87 88 89 90 91 92 93 94 95 96 97

View Code