【最近公共祖先+二分答案】运输计划

答案问的是最小值且取值具有单调性,所以可以二分。

首先可以确定虫洞一定在所有耗费时间超过mid的计划路径的交集上,把所有计划按花费时间来从大到小排序就可以很容易找出它们。

在check中用一个d[x]数组标记从x到根节点的路径被走了几次,d[u]++,d[v]++,d[lca]-=2,然后调用dfscheck回溯d数组求和即可求出交集。

最后在交集上尝试添加虫洞,如果新添加的虫洞能使原来耗费时间最大的计划能在mid时间以内完成,那么剩余所有的计划也都能按时完成,这时直接返回特殊值使所有dfscheck跳出。

注意n<=300000,所以求LCA时最大倍增次数为19

二分答案一定要用以下格式,要不然很容易陷入死循环或者得不到最优解
 while(l<=r)
 {
  mid=(l+r)/2;
  if (check())
  {
   ans=mid;
   r=mid-1;
  }
  else
   l=mid+1;
 }

  1 #define stack_size (20001000)
  2 int stack[stack_size],bak;
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <cstring>
  6 using namespace std;
  7 int n,m,a,b,w,u,v,mid,fir[300001],dep[300001],f[300001][20],wsum[300001][20],d[300001],sz=0,r=0,chkcnt,root=1;
  8 struct TE{int next,to,w;}te[600001];
  9 struct PLAN{int u,v,lca,w;}plan[300001];
 10 inline int read(int &x)
 11 {
 12     char ls=getchar();x=0;
 13     for (;ls<‘0‘||ls>‘9‘;ls=getchar());
 14     for (;ls>=‘0‘&&ls<=‘9‘;ls=getchar())x=x*10+ls-‘0‘;
 15     return x;
 16 }
 17 inline void adde(int &u,int &v,int &w)
 18 {
 19     te[++sz].next=fir[u];
 20     fir[u]=sz;
 21     te[sz].to=v;
 22     te[sz].w=w;
 23 }
 24 inline void dfs(int &x,int &p)
 25 {
 26     for (int i=1;i<=19;i++)
 27     {
 28         if ((1<<i)>dep[x]) break;
 29         f[x][i]=f[f[x][i-1]][i-1];
 30         wsum[x][i]=wsum[x][i-1]+wsum[f[x][i-1]][i-1];
 31     }
 32     for (int i=fir[x];i;i=te[i].next)
 33         if (te[i].to!=p)
 34         {
 35             dep[te[i].to]=dep[x]+1;
 36             f[te[i].to][0]=x;
 37             wsum[te[i].to][0]=te[i].w;
 38             dfs(te[i].to,x);
 39         }
 40 }
 41 inline void lca()
 42 {
 43     for (int i=1;i<=m;i++)
 44     {
 45         int a=plan[i].u,b=plan[i].v,&ww=plan[i].w;
 46         if (dep[a]>dep[b]){int t=a;a=b;b=t;}
 47         int t=dep[b]-dep[a];
 48         for (int j=19;j>=0;j--)
 49             if (t&(1<<j))
 50             {
 51                 ww+=wsum[b][j];
 52                 b=f[b][j];
 53             }
 54         for (int j=19;j>=0;j--)
 55             if (f[a][j]!=f[b][j])
 56             {
 57                 ww+=wsum[a][j]+wsum[b][j];
 58                 a=f[a][j],b=f[b][j];
 59             }
 60         if (a==b)
 61             plan[i].lca=a;
 62         else
 63         {
 64             ww+=wsum[a][0]+wsum[b][0];
 65             plan[i].lca=f[a][0];
 66         }
 67         if (ww>r) r=ww;
 68     }
 69 }
 70 inline bool cmp(PLAN a,PLAN b)
 71 {return a.w>b.w;}
 72 inline int dfscheck(int &x,int &p)
 73 {
 74     int dsum=0,t;
 75     for (int i=fir[x];i;i=te[i].next)
 76         if (te[i].to!=p)
 77         {
 78             t=dfscheck(te[i].to,x);
 79             if (t==-1) return -1;
 80             if (t==chkcnt&&plan[1].w-te[i].w<=mid) return -1;
 81             dsum+=t;
 82         }
 83     return dsum+d[x];
 84 }
 85 inline bool check()
 86 {
 87     memset(d,0,sizeof(d));
 88     chkcnt=0;
 89     for (int i=1;i<=m;i++)
 90     {
 91         if (plan[i].w<=mid) break;
 92         chkcnt++;
 93         d[plan[i].u]++;
 94         d[plan[i].v]++;
 95         d[plan[i].lca]-=2;
 96     }
 97     if (dfscheck(root,root)==-1) return 1;
 98     return 0;
 99 }
100 int main()
101 {
102     __asm__ __volatile__
103     (
104         "mov %%esp,%0\n"
105         "mov %1,%%esp\n"
106         :"=g"(bak)
107         :"g"(stack+stack_size-1)
108         :
109     );
110     read(n);read(m);
111     for (int i=1;i<n;i++)
112     {
113         read(u);read(v);read(w);
114         adde(u,v,w);
115         adde(v,u,w);
116     }
117     dfs(root,root);
118     for (int i=1;i<=m;i++)
119         read(plan[i].u),read(plan[i].v);
120     lca();
121     sort(plan+1,plan+m+1,cmp);
122     int l=0,ans;
123     while(l<=r)
124     {
125         mid=(l+r)/2;
126         if (check())
127         {
128             ans=mid;
129             r=mid-1;
130         }
131         else
132             l=mid+1;
133     }
134     printf("%d",ans);
135     return 0;
136 }
时间: 2024-10-07 08:58:41

【最近公共祖先+二分答案】运输计划的相关文章

[NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去.显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰. 为了鼓励科技创新,L国国王同意小P的物流

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

P2680 运输计划[二分+LCA+树上差分]

题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n?1 条双向航道,每条航道建立在两个星球之间,这 n-1n?1 条航道连通了 LL 国的所有星球. 小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_i*u**i* 号星球沿最快的宇航路径飞行到 v_i*v**i* 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_j*t**j*,并且任意两艘飞船之间不会产生任

NOIP2015 运输计划(二分+LCA+差分)

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

noip 2015 运输计划 (lca+二分)

/* 95 最后一个点T了 qian lv ji qiong 了 没学过树剖 听chx听xzc说的神奇的方法 Orz 首先求出每个计划的路径长度 这里写的倍增 然后二分答案 对于每个ans 统计>他的路径条数 tot 并维护最大差值 dec 并且对于每条不合法的路径维护每个点的经过次数 然后枚举点 如果经过次数==tot说明每一条不合法的都经过他 然后尝试把它建成虫洞 如果他对应边的权值>=dec 那么我们删掉它ans就合法了 关键是统计每个点在非法路径中的经过次数 : 维护sum数组 对于每

【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】

[题目大意] 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. [字符串hash的小笔记] hash[i]=(hash[i-1]*p+idx(s[i]))%mod,idx为映射值,一般a..z映射1..26: 习惯上,p取一个6到8位的素数即可,mod一般取大素数 1e9+7(1000000007)或1e9+9(1000000009). hash[i]=(hash[i-1]*p+idx(s[i]))%mod 表示第 i 个前缀的hash值,是一个hash的前缀和,那么,要求S[l…r]

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍. 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界:不存在就缩小上界): 2)主要是对答案的判断(judge函数

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰.为了鼓励科技创新, L