zoukankan      html  css  js  c++  java
  • 洛谷P2680 运输计划(树上差分+二分)

    传送门

    考虑树上乱搞

    首先这是满足二分性质的,如果在某个时间可以完成工作那么比他更长的时间肯定也能完成工作

    然后考虑二分,设当前答案为$mid$,如果有一条链的长度大于$mid$,那么这条链上必须得删去一条边。我们可以贪心的删去所有可以删去的边中最长的,然后看看最长边减去删去的边是否小于等于$mid$,如果成立说明可行

    然后考虑怎么solve,我们可以用树上差分,就是对于每个点把它看做他父亲到他的边,每个点记录一个$s$,然后对于一条链,两个端点++,lca-=2。如果有一个点的$s$等于大于$mid$的链的条数,说明它被所有的链给覆盖,然后求一个最大值就好了

    然后每一条链的lca都要求出来……实际上直接每一条都$O(logn)$求出来也没关系……不过代码里用的是tarjan离线求的,所以复杂度是$O(n+m)$

    总复杂度是$O(nlogn)$(复杂度并没有降……直接树剖求LCA可能更省力啊……)

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<21],*p1=buf,*p2=buf;
     8 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
     9 inline int read(){
    10     #define num ch-'0'
    11     char ch;bool flag=0;int res;
    12     while(!isdigit(ch=getc()))
    13     (ch=='-')&&(flag=true);
    14     for(res=num;isdigit(ch=getc());res=res*10+num);
    15     (flag)&&(res=-res);
    16     #undef num
    17     return res;
    18 }
    19 const int N=3e5+5;
    20 int head[N],Next[N<<1],ver[N<<1],edge[N<<1],tot;
    21 int hq[N<<1],nq[N<<1],vq[N<<1],tq;
    22 int dis[N],a[N],fa[N],s[N],vis[N];
    23 int n,mx,ans,res,num,m;
    24 struct node{
    25     int u,v,len,lca;
    26     node(){}
    27     node(int u,int v,int len,int lca):u(u),v(v),len(len),lca(lca){}
    28     inline void solve(){++s[u],++s[v],s[lca]-=2;}
    29 }q[N];
    30 inline void add(int u,int v,int e){
    31     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
    32 }
    33 inline void addq(int u,int v){
    34     vq[++tq]=v,nq[tq]=hq[u],hq[u]=tq;
    35 }
    36 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    37 void dfs(int u,int fa){
    38     for(int i=head[u];i;i=Next[i]){
    39         int v=ver[i];
    40         if(v!=fa){
    41             dfs(v,u),s[u]+=s[v];
    42         }
    43     }
    44     if(s[u]==num) cmax(res,a[u]);
    45 }
    46 bool check(int x){
    47     memset(s,0,sizeof(s));
    48     num=res=0;
    49     for(int i=1;i<=m;++i)
    50     if(q[i].len>x){
    51         q[i].solve(),++num;
    52     }
    53     dfs(1,0);
    54     return mx-res<=x;
    55 }
    56 void tarjan(int u,int ff){
    57     for(int i=head[u];i;i=Next[i]){
    58         int v=ver[i];
    59         if(v==ff) continue;
    60         dis[v]=dis[u]+edge[i];
    61         tarjan(v,u);
    62         a[v]=edge[i];
    63         int f1=find(v),f2=find(u);
    64         if(f1!=f2) fa[f1]=f2;
    65         vis[v]=1;
    66     }
    67     for(int i=hq[u];i;i=nq[i]){
    68         int v=vq[i];
    69         if(vis[v]){
    70             int p=(i+1)>>1,LCA=find(v);
    71             q[p]=node(u,v,dis[u]+dis[v]-2*dis[LCA],LCA);
    72             cmax(mx,q[p].len);
    73         }
    74     }
    75 }
    76 int main(){
    77 //    freopen("testdata.in","r",stdin);
    78     n=read(),m=read();
    79     for(int i=1,u,v,e;i<n;++i)
    80     u=read(),v=read(),e=read(),add(u,v,e),add(v,u,e);
    81     for(int i=1;i<=n;++i) fa[i]=i;
    82     for(int i=1,u,v;i<=m;++i)
    83     u=read(),v=read(),addq(u,v),addq(v,u);
    84     tarjan(1,0);
    85     int l=0,r=mx,mid;
    86     while(l<=r){
    87         mid=(l+r)>>1;
    88         if(check(mid)) r=mid-1,ans=mid;
    89         else l=mid+1;
    90     }
    91     printf("%d
    ",ans);
    92     return 0;
    93 }
  • 相关阅读:
    内部类
    抽象类与接口
    多态
    继承
    封装
    创建对象的内存分析
    构造器
    面向对象 类与对象
    uniapp跳转
    uniapp-组件引用错误,仅支持 import 方式引入组件
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9677581.html
Copyright © 2011-2022 走看看