ioi 2011 race 树分治

题意:

  举办IOI2011 的同时,pattaya 还在举办2011 年国际奥林匹克长跑比赛(IOR)。作为东道主,我们需要找到最佳比赛线路。
  在Pattaya-Chonburi 范围内有N 个城市,它们通过N-1 条双向的高速公路相互连通,每条高速公路的长度是一个整数(单位:公里),它连接2 个不同的城市。注意:连接任何两个城市之间的路径有且仅有一条,即只有一条路径从一个城市到另一城市,该路径由一系列的高速公路组成,且路径上的任何一个城市都只能经过一次。
  IOR 要求的比赛线路是一条总长度为K 公里的路径,且该路径的起点城市和终点城市不同。任何一条高速公路只可能在比赛线路上出现一次,任何一个城市也只能在比赛线路上
出现一次。最佳比赛线路是指包含的高速公路数目最少的线路。 

  求最佳比赛线路中高速公路的数目,如果不存在符合条件的比赛线路,输出-1。

思路:树分治

  1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #include<cstring>
5 #include<algorithm>
6 using namespace std;
7 #define NMAX 200011
8 struct node
9 {
10 int num,weight;
11 node *next;
12 };
13 pair<int,int> d1[NMAX],d2[NMAX];
14 node *graph[NMAX];
15 node memo[2*NMAX];
16 int size[NMAX],Q[NMAX],mark[NMAX];
17 int n,m,ans=NMAX,top=0,root,sumsize,minsize,tot1,tot2;
18 void add(int x,int y,int z)
19 {
20 node *p=&memo[top++];
21 p->num=y; p->weight=z; p->next=graph[x]; graph[x]=p;
22 p=&memo[top++];
23 p->num=x; p->weight=z; p->next=graph[y]; graph[y]=p;
24 }
25 void get_root(int i,int fa)
26 {
27 int big=-1;
28 size[i]=1;
29 for(node *p=graph[i];p;p=p->next)
30 if(p->num!=fa)
31 {
32 get_root(p->num,i);
33 size[i]+=size[p->num];
34 if(size[p->num]>big) big=size[p->num];
35 }
36 if(sumsize-size[i]>big) big=sumsize-size[i];
37 if(big<minsize) minsize=big,root=i;
38 }
39 void get_dis(int i,pair<int,int> d[], int &tot)
40 {
41 int left,right,u;
42 Q[left=right=1]=i;
43 d[++tot].first=0; d[tot].second=0; mark[i]=tot;
44 while(left<=right)
45 {
46 u=Q[left++];
47 for(node *p=graph[u];p;p=p->next)
48 if(mark[p->num]==0)
49 {
50 d[++tot].first=d[mark[u]].first+p->weight; d[tot].second=d[mark[u]].second+1;
51 mark[p->num]=tot;
52 Q[++right]=p->num;
53 }
54 }
55 for(i=1;i<=right;i++) mark[Q[i]]=0;
56 }
57
58 void count(int x,node *mid)
59 {
60 node *mid_next=mid->next,*left=graph[x];
61 tot2=tot1=0;
62 mid->next=NULL;
63 get_dis(x,d1,tot1);
64 sort(d1+2,d1+tot1+1);
65 mid->next=mid_next; graph[x]=mid_next;
66 get_dis(x,d2,tot2);
67 sort(d2+2,d2+tot2+1);
68 for(int i=1,j=tot2;i<=tot1;i++)
69 {
70 while(d1[i].first+d2[j].first>m&&j>0) j--;
71 while(d1[i].first+d2[j].first==m)
72 {
73 if(ans>d1[i].second+d2[j].second) ans=d1[i].second+d2[j].second;
74 if(j>0&&d2[j-1].first==d2[j].first) j--;
75 else break;
76 }
77 }
78 graph[x]=left;
79 }
80
81 void dfs(int i,int size_i)
82 {
83 if(size_i<=2) return ;
84 sumsize=minsize=size_i;
85 get_root(i,-1); i=root;
86 get_root(i,-1);
87 int sum=0;
88 node *mid,*mid_next,*left=graph[i],*p;
89 for(p=graph[i];p;p=p->next)
90 {
91 sum+=size[p->num];
92 if(sum*2>=size_i-1||p->next->next==NULL) break;
93 }
94 mid=p;
95 count(i,mid);
96 mid_next=mid->next; mid->next=NULL;
97 dfs(i,sum+1);
98 mid->next=mid_next; graph[i]=mid_next;
99 dfs(i,size_i-sum);
100 graph[i]=left;
101 }
102
103 int main()
104 {
105 int x,y,z;
106 scanf("%d%d",&n,&m);
107 memset(mark,0,sizeof(mark));
108 memset(graph,0,sizeof(graph));
109 int i;
110 for(i=1;i<n;i++)
111 {
112 scanf("%d%d%d",&x,&y,&z);
113 add(x,y,z);
114 }
115 dfs(0,n);
116 if(ans!=NMAX)
117 printf("%d\n",ans);
118 else
119 printf("-1\n");
120 return 0;
121 }



原文地址:https://www.cnblogs.com/myoi/p/2418674.html