[IOI2011]Race

Posted zhy12138

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[IOI2011]Race相关的知识,希望对你有一定的参考价值。

毕竟是人生第一道IOI(现在已经挂了又A了~~),就认真写一写吧。

竟然有爆栈这种操作(亏我花了一个多小时优化时间以为RE是TLE

题面一看就是淀粉质。(感觉好裸)

以下是同学的挂掉做法

技术分享图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 template<class T>
  4 inline void read(T &a)
  5 {
  6     T s = 0, w = 1;
  7     char c = getchar();
  8     while(c < 0 || c > 9)
  9     {
 10         if(c == -) w = -1;
 11         c = getchar();
 12     }
 13     while(c >= 0 && c <= 9)
 14     {
 15         s = (s << 1) + (s << 3) + (c ^ 48);
 16         c = getchar();
 17     }
 18     a = s*w;
 19 } 
 20 struct edge{
 21     int from,to,cost,net;
 22     edge(int f = 0, int t = 0, int c = 0, int n = 0)
 23     {
 24         from = f;
 25         to = t;
 26         cost = c;
 27         net = n;
 28     }
 29 }edges[101010];
 30 int head[101010],tot,k,n;
 31 void add(int x, int y, int c)
 32 {
 33     edges[++tot] = edge(x,y,c,head[x]);
 34     head[x] = tot;
 35 }
 36 int root = 0;
 37 int vis[101010],mx[10101],size[101010],S;
 38 void find(int x, int fa)
 39 {
 40     size[x] = 1;mx[x] = 0;
 41     for (int i = head[x];i;i = edges[i].net)
 42     {
 43         edge v = edges[i];
 44         if(vis[v.to] || v.to == fa) continue;
 45         find(v.to,x);
 46         size[x] += size[v.to];
 47         mx[x] = max(mx[x],size[v.to]);
 48     }
 49     mx[x] = max(mx[x],S-size[x]);
 50     if(mx[x] < mx[root])
 51     {
 52         root = x;
 53     }
 54 }
 55 int cnt,dis[10101],deep[101010];
 56 int minn = 0x3f3f3f3f;
 57 int ans = 0;
 58 void get_dis(int x,int fa,int len,int k)
 59 {
 60     dis[++cnt] = len;
 61     deep[cnt] = k;
 62     for (int i = head[x];i;i = edges[i].net)
 63     {
 64         edge v = edges[i];
 65         if(vis[v.to]||v.to == fa) continue;
 66         get_dis(v.to,x,len+v.cost,k+1);
 67     }
 68 }
 69 void solve(int x,int len, int pp)
 70 {
 71     cnt = 0;
 72     get_dis(x,0,len,0);
 73     sort(dis+1,dis+1+cnt);
 74     int l = 1,r = cnt;
 75     while(l <= r)
 76     {
 77         if(dis[l] + dis[r] == k)
 78         {
 79             ans += pp;
 80             if(deep[l] + deep[r] < minn)
 81             {
 82                 minn = deep[l] + deep[r];
 83             }
 84             break;
 85         }
 86         if(dis[l] + dis[r] < k) l++;
 87         if(dis[l] + dis[r] > k) r--;
 88 
 89     }
 90     /*for (int i = 1; i <= cnt; i++)
 91     {
 92         for (int j = 1; j <= cnt; j++)
 93         {
 94             if(dis[i] + dis[j] == k) ans += pp;
 95         }
 96     }*/
 97 }
 98 void Divide(int x)
 99 {
100     solve(x,0,1);
101     vis[x] = 1;
102     for (int i = head[x];i;i = edges[i].net)
103     {
104         edge v = edges[i];
105         if(vis[v.to]) continue;
106         solve(v.to,v.cost,-1);
107         S = size[v.to]; root = 0;
108         find(v.to,x);
109     //    printf("%d
",root);
110         Divide(root);
111     }
112 }
113 int main()
114 {
115     read(n); read(k);
116     for (int i = 1; i < n; i++)
117     {
118         int x,y,z;
119         read(x); read(y); read(z);
120         x++;y++;
121         add(x,y,z);
122         add(y,x,z);
123     }
124     root = 0;
125     mx[root] = n+1;
126     S = n;
127     find(1,0);
128     //printf("%d
",root);
129     Divide(root);
130     printf("%d
",ans == 0? -1 : minn);
131     return 0;
132 }
View Code

该算法挂掉的主要原因在于使用计数器记录最小值时,一个元素无法处理错误路径这种骚操作。

于是蒟蒻的我想到了开一个大数组来计数(这TM不就是桶排吗

于是我就自信地打上了如下代码

技术分享图片
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<iomanip>
  6 #include<cstring>
  7 #include<algorithm>
  8 #include<ctime>
  9 #define ll long long
 10 using namespace std;
 11 inline ll read()
 12 {
 13     ll kkk=0;
 14     int x=1;
 15     char c=getchar();
 16     while(c<0 || c>9)
 17     {
 18         if(c==-)
 19             x=-1;
 20         c=getchar();
 21     }
 22     while(c>=0 && c<=9)
 23         kkk=(kkk<<3)+(kkk<<1)+(c-0),c=getchar();
 24     return kkk*x;
 25 }
 26 struct sb
 27 {
 28     int to,l,nextn;
 29 }a[200001];
 30 int n,k,num,maxn,root,z,tot,head[200001],size[200001],maxsize[200001],ans[200001],dis[200001][2];
 31 char pd[200001];
 32 inline int ADD(int from,int to,int l)
 33 {
 34     ++tot;
 35     a[tot].to=to,a[tot].l=l,a[tot].nextn=head[from],head[from]=tot;
 36 }
 37 inline int find(int u,int fa)
 38 {
 39     size[u]=1,maxsize[u]=0;
 40     for(register int i=head[u];i!=0;i=a[i].nextn)
 41     {
 42         int v=a[i].to;
 43         if(v==fa || pd[v]==1)
 44             continue;
 45         find(v,u);
 46         size[u]+=size[v],maxsize[u]=max(maxsize[u],size[v]);
 47     }
 48     maxsize[u]=max(maxsize[u],z-size[u]);
 49     if(maxsize[u]<maxn)
 50         root=u,maxn=maxsize[u];
 51 }
 52 inline int run(int u,int fa,int l,int deep)
 53 {
 54     dis[++num][0]=l,dis[num][1]=deep;
 55     for(register int i=head[u];i!=0;i=a[i].nextn)
 56     {
 57         int v=a[i].to;
 58         if(v==fa || pd[v]==1)
 59             continue;
 60         run(v,u,l+a[i].l,deep+1);
 61     }
 62 }
 63 inline int fun(int Root)
 64 {
 65     pd[Root]=1;
 66     num=0;
 67     run(Root,-1,0,0);
 68     for(register int i=1;i<=num;++i)
 69         for(register int j=i;j<=num;++j)
 70             if(dis[i][0]+dis[j][0]==k)
 71                 ++ans[dis[i][1]+dis[j][1]];
 72     for(register int i=head[Root];i!=0;i=a[i].nextn)
 73     {
 74         int v=a[i].to;
 75         if(pd[v]==1)
 76             continue;
 77         num=0;
 78         run(v,Root,a[i].l,1);
 79         for(register int j=1;j<=num;++j)
 80             for(register int w=j;w<=num;++w)
 81                 if(dis[j][0]+dis[w][0]==k)
 82                     --ans[dis[j][1]+dis[w][1]];
 83         maxn=0x7f7f7f7f,root=-1,z=size[v];
 84         find(v,Root);
 85         fun(root);
 86     }
 87 }
 88 int main()
 89 {
 90     n=read(),k=read();
 91     for(register int i=1;i<n;++i)
 92     {
 93         int u=read(),v=read(),k=read();
 94         ADD(u,v,k),ADD(v,u,k);
 95     }
 96     maxn=0x7f7f7f7f,root=-1,z=n;
 97     find(0,-1);
 98     fun(root);
 99     for(register int i=0;i<=n;++i)
100         if(ans[i]!=0)
101         {
102             printf("%d
",i);
103             return 0;
104         }
105     putchar(-);
106     putchar(1);
107     putchar(
);
108     return 0;
109 }
View Code

 

和之前那份代码明显码风不同吧

 

结果我尴尬地只拿了10分,蒟蒻的我开始沉思————这么高级的方法怎么会挂呢???(WTF,除了点分治高级外就全是枚举好吧

其实我只是想检查算法正确性玩玩而已(啊啊,别打

以上代码挂掉的主要原因是计数那一段太慢了,没错就是下面这一段

技术分享图片
1     num=0;
2     run(Root,-1,0,0);
3     for(register int i=1;i<=num;++i)
4         for(register int j=i;j<=num;++j)
5             if(dis[i][0]+dis[j][0]==k)
6                 ++ans[dis[i][1]+dis[j][1]];
View Code
 

于是我排了个序,用用两个指针找了下合法方案,并用last记录没次二号指针的最大位置+1就过了

PS:注意路径长度之和完全可以相等,所以找到合法方案后要向下循环求解应该会被卡成跟之前那段一样的时间(离散化可以优化)

技术分享图片
 1     num=0;
 2     run(Root,-1,0,0);
 3     sort(dis+1,dis+num+1,cmp);  //为了排序,我把之前的dis[][0]和dis[][1]放在了struct里面
 4     int last=1;
 5     for(;last<=num & dis[1].l+dis[last].l<=k;++last);   //这里有个分号!!!
 6     for(register int i=1;i<=num & dis[i].l*2<k;++i)
 7     {
 8         int j=last-1;
 9         while(j>=i)
10         {
11             int P=dis[i].l+dis[j].l;
12             if(P<=k)
13             {
14                 last=j+1;
15                 if(P==k)
16                 {
17                     ++ans[dis[i].deep+dis[j].deep];
18                     while(dis[j-1].l==dis[j].l & j>i)
19                         --j,++ans[dis[i].deep+dis[j].deep];
20                 }
21                 break;
22             }
23             --j;
24         }
25     }
View Code

不过我觉得last的初始化太暴力,就用二分查找小优化了以下,那都是后话了

好吧接下来是AC代码(至少以前是的现在也是)

技术分享图片
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<iomanip>
  6 #include<cstring>
  7 #include<algorithm>
  8 #include<ctime>
  9 #define ll long long
 10 using namespace std;
 11 inline int read()
 12 {
 13     int kkk=0;
 14     int x=1;
 15     char c=getchar();
 16     while(c<0 || c>9)
 17     {
 18         if(c==-)
 19             x=-1;
 20         c=getchar();
 21     }
 22     while(c>=0 && c<=9)
 23         kkk=(kkk<<3)+(kkk<<1)+(c-0),c=getchar();
 24     return kkk*x;
 25 }
 26 struct sb
 27 {
 28     int to,l,nextn;
 29 }a[400001];
 30 int n,k,num,maxn,root,z,tot,head[400001],size[400001],maxsize[400001],ans[400001];
 31 struct tmd
 32 {
 33     int l,deep;
 34 }dis[400001];
 35 char pd[400001];
 36 inline int cmp(tmd x,tmd y)
 37 {
 38     return x.l<y.l;
 39 }
 40 inline int ADD(int from,int to,int l)
 41 {
 42     ++tot;
 43     a[tot].to=to,a[tot].l=l,a[tot].nextn=head[from],head[from]=tot;
 44 }
 45 inline int find(int u,int fa)
 46 {
 47     size[u]=1,maxsize[u]=0;
 48     for(register int i=head[u];i;i=a[i].nextn)
 49     {
 50         int v=a[i].to;
 51         if(v==fa | pd[v])
 52             continue;
 53         find(v,u);
 54         size[u]+=size[v],maxsize[u]=(maxsize[u]>size[v]?maxsize[u]:size[v]);
 55     }
 56     maxsize[u]=(maxsize[u]>z-size[u]?maxsize[u]:z-size[u]);
 57     if(maxsize[u]<maxn)
 58         root=u,maxn=maxsize[u];
 59 }
 60 inline int run(int u,int fa,int l,int deep)
 61 {
 62     dis[++num].l=l,dis[num].deep=deep;
 63     for(register int i=head[u];i;i=a[i].nextn)
 64     {
 65         int v=a[i].to;
 66         if(v==fa | pd[v])
 67             continue;
 68         run(v,u,l+a[i].l,deep+1);
 69     }
 70 }
 71 inline int fun(int Root)
 72 {
 73     pd[Root]=1,num=0,run(Root,-1,0,0),sort(dis+1,dis+num+1,cmp);
 74     int last,l=1,r=num;
 75     while(l<r)
 76     {
 77         int mid=(l+r)/2;
 78         if(dis[1].l+dis[mid].l<=k)
 79             l=mid+1;
 80         else
 81             r=mid;
 82     }
 83     last=l;
 84     if(last==num & dis[1].l+dis[last].l<=k)
 85         ++last;
 86     for(register int i=1;i<=num & dis[i].l*2<k;++i)
 87     {
 88         int j=last-1;
 89         while(j>=i)
 90         {
 91             int P=dis[i].l+dis[j].l;
 92             if(P<=k) 
 93             {
 94                 last=j+1;
 95                 if(P==k)
 96                 {
 97                     ++ans[dis[i].deep+dis[j].deep];
 98                     while(dis[j-1].l==dis[j].l & j>i)
 99                         --j,++ans[dis[i].deep+dis[j].deep];
100                 }
101                 break;
102             }
103             --j;
104         }
105     }
106     for(register int i=head[Root];i;i=a[i].nextn)
107     {
108         int v=a[i].to;
109         if(pd[v])
110             continue;
111         num=0,run(v,Root,a[i].l,1),sort(dis+1,dis+num+1,cmp);
112         l=1,r=num;
113         while(l<r)
114         {
115             int mid=(l+r)/2;
116             if(dis[1].l+dis[mid].l<=k)
117                 l=mid+1;
118             else
119                 r=mid;
120         }
121         last=l;
122         if(last==num & dis[1].l+dis[last].l<=k)
123             ++last;
124         for(register int j=1;j<=num & dis[j].l*2<k;++j)
125         {
126             int w=last-1;
127             while(w>=j)
128             {
129                 int P=dis[j].l+dis[w].l;
130                 if(P<=k)
131                 {
132                     last=w+1;
133                     if(P==k)
134                     {
135                         --ans[dis[j].deep+dis[w].deep];
136                         while(dis[w-1].l==dis[w].l & w>j)
137                             --w,--ans[dis[j].deep+dis[w].deep];
138                     }
139                     break;
140                 }
141                 --w;
142             }
143         }
144         maxn=0x7f7f7f7f,root=-1,z=size[v],find(v,Root),fun(root);
145     }
146 }
147 int main()
148 {
149     n=read(),k=read();
150     for(register int i=1;i<n;++i)
151     {
152         int u=read(),v=read(),k=read();
153         ADD(u,v,k),ADD(v,u,k);
154     }
155     maxn=0x7f7f7f7f,root=-1,z=n;
156     find(0,-1),fun(root);
157     for(register int i=0;i<=n;++i)
158         if(ans[i])
159         {
160             printf("%d
",i);
161             return 0;
162         }
163     putchar(-);
164     putchar(1);
165     putchar(
);
166     return 0;
167 }
View Code

后记:

洛谷评测姬更新以后空间好像变少了,所以我的栈空间被卡爆了,大数据连找重心都跑不过。所以还需要打手动模拟栈来优化,但太麻烦了。(2018.8)

我今天好像发现把能换int类型的函数换成void就能过了。(2018.10.30)

以上是关于[IOI2011]Race的主要内容,如果未能解决你的问题,请参考以下文章

P4149 [IOI2011]Race

点分治 [IOI2011]Race

Luogu4149 [IOI2011]Race

[IOI2011]Race

bzoj 2599 [IOI2011]Race (点分治)

[BZOJ2599][Race][IOI2011]点分治