zoukankan      html  css  js  c++  java
  • 【NOIP2015】运输计划

    先化边权为点权,然后二分答案mid

    check的时候对于每一个mid,我们把长度超过mid的路径标记一下然后按点差分一下

    假设最长的路径长度是maxn,有num条路径的长度大于mid,那么显然删掉的那条边需要贡献的次数也必须为num,否则必然会至少有一段仍然大于mid

    如果maxn减去删掉的那条边还是比mid大,那么显然不行,要尝试更大的答案,否则试试更小的行不行

    关于求每条路径的长度,可以用tarjan求解(但是我不会),所以这里采用了树剖求解(两个log,可能有点小卡)

      1 #include<bits/stdc++.h>
      2 #define writeln(x)  write(x),puts("")
      3 #define writep(x)   write(x),putchar(' ')
      4 using namespace std;
      5 inline int read(){
      6     int ans=0,f=1;char chr=getchar();
      7     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
      8     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
      9     return ans*f;
     10 }void write(int x){
     11     if(x<0) putchar('-'),x=-x;
     12     if(x>9) write(x/10);
     13     putchar(x%10+'0');
     14 }const int M = 6E+5;
     15 int head[M],ver[M],val[M],nxt[M],tot,n,m,st[M],ed[M],maxn,len[M];
     16 inline void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot,val[tot]=z;}
     17 namespace T_S{//树剖部分,区间求和,不带修,板子不讲了
     18     int idx[M],fa[M],dep[M],sz[M],son[M],tp[M],T,a[M],b[M];
     19     void dfs1(int x,int f){
     20         dep[x]=dep[f]+1,fa[x]=f,sz[x]=1;
     21         for(int i=head[x];i;i=nxt[i]){
     22             if(ver[i]==f)continue;
     23             b[ver[i]]=val[i];
     24             dfs1(ver[i],x);
     25             sz[x]+=sz[ver[i]];
     26             if(sz[ver[i]]>sz[son[x]])son[x]=ver[i];
     27         }
     28     }void dfs2(int x,int topf){
     29         tp[x]=topf,idx[x]=++T,a[T]=b[x];
     30         if(!son[x])return;
     31         dfs2(son[x],topf);
     32         for(int i=head[x];i;i=nxt[i])
     33             if(!idx[ver[i]])dfs2(ver[i],ver[i]);
     34     }inline int LCA(int x,int y){
     35         while(tp[x]!=tp[y]){
     36             if(dep[tp[x]]<dep[tp[y]])swap(x,y);
     37             x=fa[tp[x]];
     38         }return dep[x]>dep[y]?y:x;
     39     }
     40     #define ls (i<<1)
     41     #define rs (i<<1|1)
     42     #define mid (l+r>>1)
     43     int s[M<<2];
     44     inline void Push_Up(int i){s[i]=s[ls]+s[rs];}
     45     void Build(int i,int l,int r){
     46         if(l==r)return s[i]=a[l],void();
     47         Build(ls,l,mid),Build(rs,mid+1,r);
     48         Push_Up(i);
     49     }int Query(int i,int l,int r,int ql,int qr){
     50         if(ql<=l&&r<=qr)return s[i];
     51         int ans=0;
     52         if(ql<=mid)ans+=Query(ls,l,mid,ql,qr);
     53         if(qr>mid) ans+=Query(rs,mid+1,r,ql,qr);
     54         Push_Up(i);return ans;
     55     }
     56     #undef ls
     57     #undef rs
     58     #undef mid
     59     inline int Tree_Query(int x,int y){
     60         int ans=0;
     61         while(tp[x]!=tp[y]){
     62             if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
     63             ans+=Query(1,1,n,idx[tp[x]],idx[x]);
     64             x=fa[tp[x]];
     65         }if(dep[x]>dep[y]) swap(x,y);
     66         ans+=Query(1,1,n,idx[x]+1,idx[y]);
     67         return ans;
     68     }
     69 }int s[M],num,res;
     70 void dfs(int x,int fa){
     71     for(int i=head[x];i;i=nxt[i]){
     72         if(fa==ver[i])continue;
     73         dfs(ver[i],x);
     74         s[x]+=s[ver[i]];
     75     }if(s[x]==num&&T_S::b[x]>res)res=T_S::b[x];//s[x]表示这个点被经过的次数,res表示在这个前提下最大的点权
     76 }inline bool check(int x){
     77     memset(s,0,sizeof(s));num=res=0;
     78     for(int i=1;i<=m;i++)
     79         if(len[i]>x)
     80             ++num,++s[st[i]],++s[ed[i]],s[T_S::LCA(st[i],ed[i])]-=2;//按点差分,lca要-2
     81     dfs(1,0);if(maxn-res>x)return 0;
     82     return 1;
     83 }int main(){
     84     n=read(),m=read();
     85     for(int i=1;i<n;i++){
     86         int x=read(),y=read(),z=read();
     87         add(x,y,z),add(y,x,z);
     88     }T_S::dfs1(1,0),T_S::dfs2(1,1),T_S::Build(1,1,n);
     89     for(int i=1;i<=m;i++){
     90         st[i]=read(),ed[i]=read();
     91         len[i]=T_S::Tree_Query(st[i],ed[i]);//树剖把每一段路径的长度都求出来
     92         maxn=max(maxn,len[i]);
     93     }int l=0,r=maxn,ans,mid;
     94     while(l<=r){
     95         mid=l+r>>1;
     96         if(check(mid))r=mid-1,ans=mid;
     97         else l=mid+1;
     98     }cout<<ans<<endl;
     99     return 0;
    100 }
  • 相关阅读:
    梦断代码,读书计划
    《梦断代码》读后感1
    四则运算2详细过程
    四则运算2初步构思
    四则运算
    阅读《梦断代码》计划
    四则运算2设计思路
    随机输出30道四则运算题
    软件工程阅读计划
    面试题04
  • 原文地址:https://www.cnblogs.com/zhenglw/p/11686313.html
Copyright © 2011-2022 走看看