题目链接: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