• 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 }



  • 相关阅读:
    luogu P3168 [CQOI2015]任务查询系统
    luogu P2633 Count on a tree
    c++小游戏:洛谷彩票
    UVA514 铁轨 Rails:题解
    SP1805 HISTOGRA
    洛谷 P4363 [九省联考2018]一双木棋chess 题解
    比赛:大奔的方案solution
    【CYH-02】NOIp考砸后虐题赛:数学:题解
    【CYH-02】NOIp考砸后虐题赛:坐标:题解
    【CYH-02】NOIp考砸后虐题赛:转换式:题解
  • 原文地址:https://www.cnblogs.com/myoi/p/2418674.html
Copyright © 2020-2023  润新知