zoukankan      html  css  js  c++  java
  • 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)求路径交(就是统计每个点被路径经过了几次,然后被经过次数与路径数相等的就属于路径交)

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

    。。。。代码以后再说吧

  • 相关阅读:
    Linux中查找当前目录下占用空间最大的前10个文件
    Redis的优势和特点
    java中final,finally,finalize三个关键字的区别
    消息队列介绍
    Redis的应用场景
    Spring中@Autowired注解与@Resource注解的区别
    多版本并发控制(MVCC)
    Linux查看CPU和内存使用情况
    进程调度算法
    一致性Hash算法
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9017766.html
Copyright © 2011-2022 走看看