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

    P2680 运输计划

    链接

    分析:

      二分+树上差分。

      首先可以二分一个答案,那么所有比这个答案大的路径,都需要减去些东西才可以满足这个答案。

      那么减去的这条边一定在所有的路径的交集上。

      那么如果求快速的求出这个交集并判断呢,树剖可以,把所有大于的路径都标记一下,然后判断,复杂度太大了。

      于是用到了树上差分,get新技能。

      在两个端点出标记+1,在lca出标记-2,然后从叶子节点往上更新,对于一条边是交集,那么它标记的次数一定是大于这个答案的个数。然后判断是否满足即可。

      各种优化:1、L,R的范围,2、可以按dis排序,发现没什么用。

    代码

      1 // luogu-judger-enable-o2
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<iostream>
      7 #include<cctype>
      8 
      9 using namespace std;
     10 
     11 const int N = 300100;
     12 struct Edge{
     13     int nxt,to,w;
     14     Edge() {}
     15     Edge(int a,int b,int c) {to = a,w = b,nxt = c;}
     16 }e[600100];
     17 struct Que{
     18     int u,v,lca,dis;
     19     bool operator < (const Que &A) const {
     20         return dis > A.dis;
     21     }
     22 }q[N];
     23 int head[N],tot;
     24 int deth[N],fa[N],num[N],dis[N],val[N],f[N][23],tag[N];
     25 int n,m,dfs_time;
     26 
     27 inline char nc() {
     28     static char buf[100000],*p1 = buf,*p2 = buf;
     29     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
     30 }
     31 inline int read() {
     32     int x = 0,f = 1;char ch = nc();
     33     for (; !isdigit(ch); ch=nc()) if(ch=='-') f=-1;
     34     for (; isdigit(ch); ch=nc()) x=x*10+ch-'0';
     35     return x * f;
     36 }
     37 void add_edge(int u,int v,int w) {
     38     e[++tot] = Edge(v,w,head[u]);head[u] = tot;
     39     e[++tot] = Edge(u,w,head[v]);head[v] = tot;
     40 }
     41 void dfs(int u,int fa) {
     42     num[++dfs_time] = u;
     43     deth[u] = deth[fa] + 1;
     44     f[u][0] = fa;
     45     for (int i=head[u]; i; i=e[i].nxt) {
     46         int v = e[i].to;
     47         if (v == fa) continue;
     48         dis[v] = dis[u] + e[i].w;
     49         val[v] = e[i].w;
     50         dfs(v,u);
     51     }
     52 }
     53 void init() {
     54     for (int j=1; j<=22; ++j) 
     55         for (int i=1; i<=n; ++i) 
     56             f[i][j] = f[f[i][j-1]][j-1];
     57 }
     58 int Lca(int u,int v) {
     59     if (deth[u] < deth[v]) swap(u,v);
     60     int d = deth[u] - deth[v];
     61     for (int i=22; i>=0; --i) 
     62         if (d & (1 << i)) u = f[u][i];
     63     if ( u == v ) return u;
     64     for (int i=22; i>=0; --i) 
     65         if (f[u][i] != f[v][i]) 
     66             u = f[u][i],v = f[v][i];
     67     return f[u][0];
     68 }
     69 bool check(int x) {
     70     memset(tag,0,sizeof(tag));
     71     int limit = 0,cnt = 0;
     72     for (int i=1; i<=m; ++i) {
     73         if (q[i].dis > x) { // 找到所有大于x的 
     74             tag[q[i].u] ++; tag[q[i].v] ++; tag[q[i].lca] -= 2; // 差分 
     75             limit = max(limit,q[i].dis - x); // 最少减去多少 
     76             cnt ++;
     77         }
     78     }
     79     if (!cnt) return true; //如果没有大于x的,直接返回true,加上这句快了不少。 
     80     for (int i=n; i>=1; --i) 
     81         tag[f[num[i]][0]] += tag[num[i]];
     82     for (int i=2; i<=n; ++i) 
     83         if (val[i] >= limit && tag[i] == cnt) return true;
     84     return false;
     85 }
     86 int main () {
     87     n = read(),m = read();
     88     int L = 0,R = 0;
     89     for (int i=1; i<n; ++i) {
     90         int u = read(),v = read(),w = read();
     91         add_edge(u,v,w);
     92         L = max(L,w);
     93     }
     94     dfs(1,0);
     95     init();
     96     for (int i=1; i<=m; ++i) {
     97         q[i].u = read(),q[i].v = read();
     98         q[i].lca = Lca(q[i].u,q[i].v);
     99         q[i].dis = dis[q[i].u] + dis[q[i].v] - dis[q[i].lca] * 2;
    100         R = max(R, q[i].dis);
    101     }
    102 //    sort(q+1,q+m+1);
    103     int ans = R;
    104     while ( L <= R )    { 
    105         int mid = ( L + R ) / 2;
    106         if (check(mid)) ans = mid,R = mid - 1;
    107         else L = mid + 1;
    108     }
    109     cout << ans;
    110     return 0;
    111 }
  • 相关阅读:
    ftp服务器架设
    samba服务器架设
    apache安装
    yum及prm安装
    redis安装与使用
    memcached安装与使用
    mysql主从服务器
    nginx负载均衡服务器搭建
    lnmp环境搭建
    linux笔记
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9096847.html
Copyright © 2011-2022 走看看