zoukankan      html  css  js  c++  java
  • BZOJ_4326_[NOIP2015]_运输计划_(二分+LCA_树链剖分/Tarjan+差分)

    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=4326

    给出一棵带有边权的树,以及一系列任务,任务是从树上的u点走到v点,代价为u到v路径上的权值之和,总代价是所有任务代价中的最大代价.现在可以将某一个边权值变为0,问总代价最小是多少.

    分析


    最小化最大值,显然可以二分,转化为假定解判断是否可行的问题.

    那么问题就转化成了判断但前假定解t是否可行.

    如何做呢?

    我们先求出每一个任务的代价,这个可以用随便什么LCA算法求,然后统计出其中超过假定解t的不合法的任务.这些不合法的任务的道路上必须有某条边的权值被该成0,但是只能改一条边,那么必须改动它们的公共边,也就是这些路径的交.

    那么如何求这些路径的交呢?

    如果我们用cnt[i]表示i和它父亲的连边被几条这样不合法的路径经过,那么我们要找的就是cnt[i]=(不合法路径数目)的边.

    这个又该怎么实现呢?一条一条路径跑?显然太慢了!

    想想如果把这个问题转化成线性的,在一个线段上的话该怎么做?

    线段树?ok的,在树上的话显然要用链剖了,这样的复杂度是带一个log的.

    有没有更好的方法?

    差分.如果[l,r]的次数要+1,我们就把l位置+1,r+1位置-1,表示给l及其之后的全部+1次,再给r+1及其之后的全部-1次.全部操作结束后从前向后扫一遍,统计前面对后面的影响即可.

    我们把这样的算法搬到树上就好了.

    树链剖分:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=300000+5;
     5 int n,m,cnt;
     6 int f[maxn],dep[maxn],sz[maxn],son[maxn],top[maxn],d[maxn],ct[maxn],head[maxn];
     7 struct edge{
     8     int to,d,next;
     9     edge(int to=0,int d=0,int next=0):to(to),d(d),next(next){}
    10 }g[maxn<<1];
    11 struct query{
    12     int u,v,lca,l;
    13 }q[maxn];
    14 inline int read(int &x){ x=0; int k=1; char c; for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-') k=-1; for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return x*k; }
    15 void add_edge(int u,int v,int d){
    16     g[++cnt]=edge(v,d,head[u]); head[u]=cnt;
    17     g[++cnt]=edge(u,d,head[v]); head[v]=cnt;
    18 }
    19 void dfs1(int u){
    20     sz[u]=1;
    21     for(int i=head[u];i;i=g[i].next){
    22         int v=g[i].to;
    23         if(v==f[u]) continue;
    24         f[v]=u; dep[v]=dep[u]+1; d[v]=d[u]+g[i].d;
    25         dfs1(v); sz[u]+=sz[v];
    26         if(sz[v]>sz[son[u]]) son[u]=v;
    27     }
    28 }
    29 void dfs2(int u){
    30     if(son[u]) top[son[u]]=top[u], dfs2(son[u]);
    31     for(int i=head[u];i;i=g[i].next){
    32         int v=g[i].to;
    33         if(v==f[u]||v==son[u]) continue;
    34         top[v]=v; dfs2(v);
    35     }
    36 }
    37 int lca(int u,int v){
    38     while(top[u]!=top[v]){
    39         if(dep[top[u]]<dep[top[v]]) swap(u,v);
    40         u=f[top[u]];
    41     }
    42     return dep[u]<dep[v]?u:v;
    43 }
    44 void update(int u){
    45     for(int i=head[u];i;i=g[i].next){
    46         int v=g[i].to;
    47         if(v==f[u]) continue;
    48         update(v);
    49         ct[u]+=ct[v];
    50     }
    51 }
    52 inline bool C(int x){
    53     int tot=0,maxi=0; memset(ct,0,sizeof ct);
    54     for(int i=1;i<=m;i++){
    55         if(q[i].l>x){
    56             tot++;
    57             ct[q[i].u]++;
    58             ct[q[i].v]++;
    59             ct[q[i].lca]-=2;
    60             maxi=max(maxi,q[i].l);
    61         }
    62     }
    63     update(1);
    64     for(int i=1;i<=n;i++)if(ct[i]==tot&&maxi-(d[i]-d[f[i]])<=x) return true;
    65     return false;
    66 }
    67 int bsearch(int l,int r){
    68     while(l<r){
    69         int mid=l+(r-l)/2;
    70         if(C(mid)) r=mid;
    71         else l=mid+1;
    72     }
    73     return l;
    74 }
    75 int main(){
    76     int maxi=0,maxj=0;
    77     read(n); read(m);
    78     for(int i=1;i<n;i++){
    79         int u,v,d; read(u); read(v); read(d);
    80         add_edge(u,v,d);
    81         maxi=max(maxi,d);
    82     }
    83     dfs1(1); dfs2(1);
    84     for(int i=1;i<=m;i++){
    85         read(q[i].u); read(q[i].v);
    86         q[i].lca=lca(q[i].u,q[i].v);
    87         q[i].l=d[q[i].u]+d[q[i].v]-2*d[q[i].lca];
    88         maxj=max(maxj,q[i].l);
    89     }
    90     printf("%d
    ",bsearch(max(0,maxj-maxi),maxj));
    91     return 0;
    92 }
    View Code

    Tarjan:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=300000+5;
     5 int n,m,cnt1,cnt2;
     6 int f[maxn],p[maxn],d[maxn],head1[maxn],head2[maxn],ct[maxn];
     7 bool vis[maxn];
     8 struct edge{
     9     int to,d,next;
    10     edge(int to=0,int d=0,int next=0):to(to),d(d),next(next){}
    11 }g[maxn<<1];
    12 struct Query{
    13     int u,v,lca,l;
    14 }Q[maxn];
    15 struct query{
    16     int v,id,next;
    17     query(int v=0,int id=0,int next=0):v(v),id(id),next(next){}
    18 }q[maxn<<1];
    19 inline int read(int &x){ x=0;int k=1;char c;for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';return x*k; }
    20 inline int find(int x){ return x==f[x]?x:f[x]=find(f[x]); }
    21 void add_edge(int u,int v,int d){
    22     g[++cnt1]=edge(v,d,head1[u]); head1[u]=cnt1;
    23     g[++cnt1]=edge(u,d,head1[v]); head1[v]=cnt1;
    24 }
    25 void add_query(int u,int v,int id){
    26     q[++cnt2]=query(v,id,head2[u]); head2[u]=cnt2;
    27     q[++cnt2]=query(u,id,head2[v]); head2[v]=cnt2;
    28 }
    29 void tarjan(int u){
    30     f[u]=u; vis[u]=true;
    31     for(int i=head1[u];i;i=g[i].next){
    32         int v=g[i].to; if(v==p[u]) continue;
    33         p[v]=u; d[v]=d[u]+g[i].d; 
    34         tarjan(v); f[v]=u;
    35     }
    36     for(int i=head2[u];i;i=q[i].next)if(vis[q[i].v]) Q[q[i].id].lca=find(q[i].v),Q[q[i].id].l=d[u]+d[q[i].v]-2*d[Q[q[i].id].lca];
    37 }
    38 void update(int u){
    39     for(int i=head1[u];i;i=g[i].next){
    40         int v=g[i].to; if(v==p[u]) continue;
    41         update(v); ct[u]+=ct[v];
    42     }
    43 }
    44 inline bool C(int x){
    45     int tot=0,maxi=0; memset(ct,0,sizeof ct);
    46     for(int i=1;i<=m;i++)if(Q[i].l>x){
    47         tot++; maxi=max(maxi,Q[i].l);
    48         ct[Q[i].u]++; ct[Q[i].v]++; ct[Q[i].lca]-=2;
    49     }
    50     update(1);
    51     for(int i=1;i<=n;i++)if(ct[i]==tot&&maxi-(d[i]-d[p[i]])<=x) return true;
    52     return false;
    53 }
    54 int bsearch(int l,int r){
    55     while(l<r){
    56         int mid=l+(r-l)/2;
    57         if(C(mid)) r=mid;
    58         else l=mid+1;
    59     }
    60     return l;
    61 }
    62 int main(){
    63     read(n); read(m);
    64     int maxi=0,maxj=0;
    65     for(int i=1;i<n;i++){
    66         int u,v,d; read(u); read(v); read(d);
    67         add_edge(u,v,d);
    68         maxi=max(maxi,d);
    69     }
    70     for(int i=1;i<=m;i++){
    71         read(Q[i].u); read(Q[i].v);
    72         add_query(Q[i].u,Q[i].v,i);
    73     }
    74     tarjan(1);
    75     for(int i=1;i<=m;i++) maxj=max(maxj,Q[i].l);
    76     printf("%d
    ",bsearch(max(0,maxj-maxi),maxj));
    77     return 0;
    78 }
    View Code

    4326: NOIP2015 运输计划

    Time Limit: 30 Sec  Memory Limit: 128 MB
    Submit: 538  Solved: 368
    [Submit][Status][Discuss]

    Description

    公 元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

    Input

    第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n

    Output

    输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

    Sample Input

    6 3
    1 2 3
    1 6 4
    3 1 7
    4 3 6
    3 5 5
    3 6
    2 5
    4 5

    Sample Output

    11

    HINT


    将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。

    将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。

    将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。

    将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。

    将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。

    故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

     

  • 相关阅读:
    强弱类型 静态语言 动态语言 || 脚本语言
    mysql版本升级问题处理
    word
    IntelliJ IDEA 插件
    dubbo
    spring源码构建
    zookeeper 本地多线程模拟分布式事务控制及配置中心
    一次性关闭所有的Activity
    可能以后用得到得东西
    Thread.sleep还是TimeUnit.SECONDS.sleep
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5598820.html
Copyright © 2011-2022 走看看