noip2015 运输计划

https://www.luogu.org/problemnew/show/P2680

首先预处理出每个计划的原时间,然后把计划按时间从小到大排序

显然,最优方案一定是选某一个计划i,记路径集合S为i以及排序后在i后面的所有计划的路径,找出S中所有路径的交集(如果交集为空则无答案),取交集中所有边上长度的最大值(交集显然一定也是一条可以只用两个端点来表示的路径),这样对于S中所有路径,都可以去掉这条边,因此此时答案为max(最长一条路径所需时间-这个最大值,排序后的第i-1条路径所需时间)

因此如果能求路径交集,那么只要按时间从大到小扫一遍即可

然后我不会求路径交。。。

搜了一下,有两种,第一种是暴力求出要求路径交的两个点对(a,b)与(c,d)共4个点之间的6对lca,显然路径交的两个端点都在这6个点中,那么枚举两个端点(x,y)然后取合法(就是满足x,y都分别在(a,b)路径上与(c,d)路径上)且(x,y)间距离最长的作为答案即可

然后超大常数、超大代码量、超大调试量、超丑代码等着我。。。。

(好像还有一种是把每条路径拆成深度单调的两条,对于四条路径两两求交,然后并起来?更麻烦的样子啊)

曾经错误:

1.22行maxn[u][i]=max(maxn[u][i-1],maxn[anc[i][i-1]][i-1]);

2.58行max(ans,maxn[a][0])【老错误了】

3.85行的||打成&&

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #define pb push_back
  5 #define fi first
  6 #define se second
  7 using namespace std;
  8 struct E
  9 {
 10     int to,nxt,d;
 11 }e[600100];
 12 int f1[300100],ne,anc[300100][30],l2n=19,dep[300100],dd[300100];
 13 int maxn[300100][30];
 14 int n,m;
 15 int lft[40];
 16 void dfs1(int u,int fa)
 17 {
 18     int i,k;
 19     for(i=1;i<=l2n;i++)
 20     {
 21         anc[u][i]=anc[anc[u][i-1]][i-1];
 22         maxn[u][i]=max(maxn[u][i-1],maxn[anc[u][i-1]][i-1]);
 23     }
 24     for(k=f1[u];k;k=e[k].nxt)
 25         if(e[k].to!=fa)
 26         {
 27             dep[e[k].to]=dep[u]+1;
 28             dd[e[k].to]=dd[u]+e[k].d;
 29             anc[e[k].to][0]=u;
 30             maxn[e[k].to][0]=e[k].d;
 31             dfs1(e[k].to,u);
 32         }
 33 }
 34 int lca(int a,int b)
 35 {
 36     if(dep[a]<dep[b])    swap(a,b);
 37     int i,t=dep[a]-dep[b];
 38     for(i=l2n;i>=0;i--)
 39         if(lft[i]<=t)
 40             a=anc[a][i],t-=lft[i];
 41     if(a==b)    return a;
 42     for(i=l2n;i>=0;i--)
 43         if(anc[a][i]!=anc[b][i])
 44             a=anc[a][i],b=anc[b][i];
 45     return anc[a][0];
 46 }
 47 int getmax(int a,int b)
 48 {
 49     if(dep[a]<dep[b])    swap(a,b);
 50     int i,t=dep[a]-dep[b],ans=0;
 51     for(i=l2n;i>=0;i--)
 52         if(lft[i]<=t)
 53             ans=max(ans,maxn[a][i]),a=anc[a][i],t-=lft[i];
 54     if(a==b)    return ans;
 55     for(i=l2n;i>=0;i--)
 56         if(anc[a][i]!=anc[b][i])
 57             ans=max(ans,maxn[a][i]),ans=max(ans,maxn[b][i]),a=anc[a][i],b=anc[b][i];
 58     return max(ans,max(maxn[a][0],maxn[b][0]));
 59 }
 60 int getdis(int a,int b)
 61 {
 62     return dd[a]+dd[b]-2*dd[lca(a,b)];
 63 }
 64 struct Q
 65 {
 66     int a,b,d;
 67 }q[300100];
 68 bool operator<(const Q &a,const Q &b)    {return a.d<b.d;}
 69 int k_anc(int a,int k)//a的k级祖先
 70 {
 71     int i;
 72     for(i=l2n;i>=0;i--)
 73         if(lft[i]<=k)
 74             a=anc[a][i],k-=lft[i];
 75     return a;
 76 }
 77 bool isanc(int a,int b)//b是否是a或a的祖先
 78 {
 79     if(dep[b]>dep[a])    return 0;
 80     return k_anc(a,dep[a]-dep[b])==b;
 81 }
 82 typedef pair<int,int> P;
 83 bool isin(int a,const P &b)//点a是否在点对b间路径上
 84 {
 85     return (isanc(b.fi,a)||isanc(b.se,a))&&!isanc(anc[lca(b.fi,b.se)][0],a);
 86 }
 87 bool isin(const P &a,const P &b)//点对a间路径是否被包含在点对b间路径中
 88 {
 89     return isin(a.fi,b)&&isin(a.se,b);
 90 }
 91 P get(const P &a,const P &b)
 92 {
 93     int tmp[]={
 94         lca(a.fi,a.se),lca(a.fi,b.fi),lca(a.fi,b.se),
 95         lca(a.se,b.fi),lca(a.se,b.se),lca(b.fi,b.se),
 96     };
 97     bool ok=0;int i,j,dd,dt;P t,ans(0,0);
 98     for(i=0;i<6;i++)
 99         for(j=i+1;j<6;j++)
100         {
101             t=P(tmp[i],tmp[j]);
102             if(isin(t,a)&&isin(t,b))
103             {
104                 if(!ok)
105                 {
106                     ok=1;ans=t;
107                     dd=dep[t.fi]+dep[t.se]-2*dep[lca(t.fi,t.se)]+1;
108                 }
109                 else
110                 {
111                     dt=dep[t.fi]+dep[t.se]-2*dep[lca(t.fi,t.se)]+1;
112                     if(dt>dd)    dd=dt,ans=t;
113                 }
114             }
115         }
116     return ans;
117 }
118 int anss;
119 int main()
120 {
121     int i,a,b,d;lft[0]=1;
122     for(i=1;i<=l2n;i++)    lft[i]=lft[i-1]<<1;
123     scanf("%d%d",&n,&m);
124     for(i=1;i<n;i++)
125     {
126         scanf("%d%d%d",&a,&b,&d);
127         e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].d=d;
128         e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].d=d;
129     }
130     dfs1(1,0);
131     for(i=1;i<=m;i++)
132     {
133         scanf("%d%d",&q[i].a,&q[i].b);
134         q[i].d=getdis(q[i].a,q[i].b);
135     }
136     sort(q+1,q+m+1);
137     //printf("a%d
",getmax(3,4));
138     P now=P(q[m].a,q[m].b);anss=max(q[m-1].d,q[m].d-getmax(q[m].a,q[m].b));
139     for(i=m-1;i>=1;i--)
140     {
141         now=get(now,P(q[i].a,q[i].b));
142         if(now==P(0,0))    break;
143         anss=min(anss,max(q[i-1].d,q[m].d-getmax(now.first,now.second)));
144     }
145     printf("%d",anss);
146     return 0;
147 }

当然还有一种方法:用树上差分显然可以O(n+m)求路径交(就是统计每个点被路径经过了几次,然后被经过次数与路径数相等的就属于路径交)

注意到答案可以二分,然后就完了。。。。。

。。。。代码以后再说吧

原文地址:https://www.cnblogs.com/hehe54321/p/9017766.html