• Vijos1983 NOIP2015Day2T3 运输计划 transport LCA


    题目链接Vijos

    题目链接UOJ

    该博客在博客园的链接

    转载一个大佬的题解:

    点击这里->大佬题解

    下面谈谈我的感悟:

    当然写代码也是写的很艰辛:

    我力劝C++的同胞们,这题卡常数,Dfs党会吃亏,比如这里这个UOJ的数据

    我们可以使用Bfs和尽量避免写Dfs,不然会Tle的

    以下代码实测极端数据约900ms,正所谓卡常数,如果把一开始的dfs改为bfs可能会更快……(博主很懒,不改了)

    总结一下大佬的题解:

    1. Dfs或Bfs构建树,然后记录下各种信息,现在主要是以下几点:

      1)子节点      son[rt]    vector <int>

      2)深度       deep[rt]    int

      3)到根节点的距离  dis[rt]    int

      4)到父亲节点的距离 fadis[rt]   int

      5)父亲       father[rt]   int

    2. LCA的预处理,处理出F[rt][i],表示节点rt的第2i个祖先(即节点rt的祖先中与之深度相差rt的祖先)    // F[rt][i]  在代码中写成 Anst[rt][i]

         转移表达式为:F[rt][i]=F[F[rt][i-1]][i-1] 应该都能够理解

    3. 求取LCA: 这里用的倍增的方法,虽然比离线算法LCA_Tarjan慢一个log,但是倍增是一个好东西,不妨去练练。这样思考:对于两个深度为d的节点a和b,使得int i=log2(d),那么就可以倍增:对于节点a和b,如果他们的第2i个祖先是相同的,那么他们在网上的祖先也一定是相同的 ,那么我们就对于不改变a和b的值,而使i=i-1;如果他们的第2i个祖先不同,那么他们往下走的祖先也是不同的,于是就可以确定他们的最近公共祖先一定是在第2i个祖先上面的,那么我们就可以安心的把a和b的值更新乘F[a][i]和F[b][i](a=F[a][i],b=F[b][i])。直到i为0位置,无法再做了。于是,a和b的最近公共祖先就是a和b的父亲,即F[a][0]或F[b][0](相等的)。于是剩下的只是把a和b调到同一深度这点事情了。设b为深度更大的那个,设deep[x]为x的深度,那么把b移上去,就是求b个第(deep[b]-deep[a])个祖先,也是倍增可以解决的。

        至于LCA_Tarjan,可以自己学啊!这里就不多说了。

    3.二分答案:不用说了吧,就是一个基本的二分

    4.check(答案):这个在大佬的题解里面写的比较详细,可以看他的~

      1 #pragma comment(linker, "/STACK:10240000,10240000")
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cstdio>
      5 #include <cstdlib>
      6 #include <cmath>
      7 #include <vector>
      8 using namespace std;
      9 const int N=300000+5,M=N*2,Inf=N*1000;
     10 void read(int &x){
     11     x=0;
     12     char ch=getchar();
     13     while (!('0'<=ch&&ch<='9'))
     14         ch=getchar();
     15     while ('0'<=ch&&ch<='9'){
     16         x=x*10+ch-48;
     17         ch=getchar();
     18     }
     19 }
     20 struct Edge{
     21     int cnt,y[M],z[M],nxt[M],fst[N];
     22     void set(){
     23         cnt=0;
     24         memset(y,0,sizeof y);
     25         memset(z,0,sizeof z);
     26         memset(nxt,0,sizeof nxt);
     27         memset(fst,0,sizeof fst);
     28     }
     29     void add(int a,int b,int c){
     30         cnt++;
     31         y[cnt]=b,z[cnt]=c;
     32         nxt[cnt]=fst[a],fst[a]=cnt;
     33     }
     34 }e;
     35 int n,m;
     36 vector <int> Tree[N];
     37 int father[N],son[N],deep[N],dis[N],fadis[N],bh[N],bhtot;
     38 int Anst[N][20];//Ancestor
     39 struct Query{
     40     int x,y,LCA,cost;
     41 }q[N];
     42 int Nextsum[N];
     43 void Build_Tree(int prev,int rt){
     44     bh[++bhtot]=rt;
     45     Tree[rt].clear();
     46     deep[rt]=deep[prev]+1;
     47     son[rt]=0;
     48     father[rt]=prev;
     49     for (int i=e.fst[rt];i;i=e.nxt[i])
     50         if (e.y[i]!=prev){
     51             son[rt]++,Tree[rt].push_back(e.y[i]);
     52             fadis[e.y[i]]=e.z[i];
     53             dis[e.y[i]]=dis[rt]+e.z[i];
     54             Build_Tree(rt,e.y[i]);
     55         }
     56 }
     57 void LCA_Prepare(){
     58     memset(Anst,0,sizeof Anst);
     59     for (int i=1;i<=n;i++){
     60         int rt=bh[i];
     61         Anst[rt][0]=father[rt];
     62         for (int i=1;(1<<i)<=deep[rt];i++)
     63             Anst[rt][i]=Anst[Anst[rt][i-1]][i-1];
     64     }
     65 }
     66 int LCA(int a,int b){
     67     if (deep[a]>deep[b])
     68         swap(a,b);
     69     for (int i=deep[b]-deep[a],j=0;i>0;i>>=1,j++)
     70         if (i&1)
     71             b=Anst[b][j];
     72     if (a==b)
     73         return a;
     74     int k;
     75     for (k=0;(1<<k)<=deep[a];k++);
     76     for (;k>=0;k--)
     77         if ((1<<k)<=deep[a]&&Anst[a][k]!=Anst[b][k])
     78             a=Anst[a][k],b=Anst[b][k];
     79     return Anst[a][0];
     80 }
     81 bool check(int t){
     82     int total=0,Maxcost=0,Maxcut=0;
     83     memset(Nextsum,0,sizeof Nextsum);
     84     for (int i=1;i<=m;i++)
     85         if (q[i].cost>t){
     86             Maxcost=max(Maxcost,q[i].cost-t);
     87             total++;
     88             Nextsum[q[i].x]++;
     89             Nextsum[q[i].y]++;
     90             Nextsum[q[i].LCA]-=2;
     91         }
     92     for (int i=n;i>=1;i--)
     93         Nextsum[father[bh[i]]]+=Nextsum[bh[i]];
     94     for (int i=1;i<=n;i++)
     95         if (Nextsum[i]==total)
     96             Maxcut=max(Maxcut,fadis[i]);
     97     return Maxcost<=Maxcut;
     98 }
     99 int main(){
    100     scanf("%d%d",&n,&m);
    101     e.set();
    102     for (int i=1;i<n;i++){
    103         int a,b,c;
    104         read(a),read(b),read(c);
    105         e.add(a,b,c);
    106         e.add(b,a,c);
    107     }
    108     bhtot=0;
    109     deep[0]=-1,dis[1]=fadis[1]=0;
    110     Build_Tree(0,1);
    111     LCA_Prepare();
    112     for (int i=1;i<=m;i++){
    113         read(q[i].x),read(q[i].y);
    114         q[i].LCA=LCA(q[i].x,q[i].y);
    115         q[i].cost=dis[q[i].x]+dis[q[i].y]-dis[q[i].LCA]*2;
    116     }
    117     int le=0,ri=Inf,mid,ans=0;
    118     while (le<=ri){
    119         mid=(le+ri)>>1;
    120         if (check(mid))
    121             ri=mid-1,ans=mid;
    122         else
    123             le=mid+1;
    124     }
    125     printf("%d",ans);
    126     return 0;
    127 }
    代码
  • 相关阅读:
    浏览器返回按钮不会触发onLoad事件
    TCP慢启动算法
    TCP协议三次握手过程分析
    关于新增和编辑
    Mock, 让你的开发脱离接口
    到底数据驱动是个什么玩意
    pagination分页插件
    关于状态切换
    在线占位图网站
    Arduino nano 与 w5500模块的连接与调试
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NOIP2015Day2T3.html
Copyright © 2020-2023  润新知