zoukankan      html  css  js  c++  java
  • 洛谷P2680运输计划

    传送门啦

    要求的就是,把树上的一条边的权值设为0之后,所有路径中的最大值的最小值。

    首先二分最大值,假设某次二分的最大值为x,我们首先找出所有大于x的路径(也就是我们需要通过改权缩短的路径),并把路径上的所有边都标记一下。

    在标记完成后,枚举所有边,如果存在一条边位于所有长度大于于x的路径上,并且删除之后能使所有路径都满足 $ length<=x $ ,则返回 $ true $ ,否则 $ false $ 。
    还有一个问题就是,对于某个路径,如何快速标记出他经过的所有边呢?我们可以使用差分,用树上前缀和来表示某个点被标记次数。比如某条边 $ E(u,v) $ ,先把 $ sum[u]+=1,sum[v]+=1 $ ,然后 $ sum[lca(u,v)]-=2 $

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define re register
    using namespace std;
    const int maxn = 300005;
    
    inline int read(){
    	char ch = getchar();
    	int f = 1 , x = 0;
    	while(ch > '9' || ch < '0'){if(ch == '-') f = -1;ch = getchar();}
    	while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
    	return x * f;
    }
    
    int n,m,a,b,t,u[maxn],v[maxn];
    int head[maxn],tot; 
    int f[maxn][21],ans;
    
    struct Edge{
    	int from,to,val,next;
    }edge[maxn << 1];
    
    inline void add(int u , int v , int w){
    	edge[++tot].from = u;
    	edge[tot].to = v;
    	edge[tot].val = w;
    	edge[tot].next = head[u];
    	head[u] = tot;
    }
    
    int dep[maxn],dis[maxn],value[maxn],len[maxn];
    int id[maxn],cnt;
    
    inline void dfs(int x , int fa) {
    	id[++cnt] = x;
    	dep[x] = dep[fa] + 1;
    	f[x][0] = fa;
    	for(re int  i = 1 ; (1 << i ) <= dep[x] ; ++i)
    		f[x][i] = f[f[x][i - 1]][i - 1];
    	for(re int i = head[x] ; i ; i = edge[i].next) {
    		int v = edge[i].to;
    		if(v == fa)  continue;
    		dis[v] = dis[x] + edge[i].val;
    		value[v] = edge[i].val;
    		dfs(v , x);
    	}
    }
    
    inline int lca(int u , int v){
    	if(dep[u] < dep[v])  swap(u , v);
    	for(re int i = 18 ; i >= 0 ; --i)
    		if((1 << i) <= (dep[u] - dep[v]))
    			u = f[u][i];
    	if(u == v)  return u;
    	for(re int i = 18 ; i >= 0 ; --i){
    		if((1 << i) <= dep[u] && f[u][i] != f[v][i]) {
    			u = f[u][i] ;
    			v = f[v][i] ;
    		}
    	}
    	return f[u][0];
    }
    
    int sum[maxn];
    
    inline bool check(int k){
    	for(re int i = 1 ; i <= n ; ++i)
    		sum[i] = 0;
    	int maxx = 0 , cnt = 0 ;
    	for(re int i = 1 ; i <= m ; ++i) {
    		if(len[i] > k) {
    			maxx = max(maxx , len[i]) ;
    			cnt++;
    			sum[u[i]]++; sum[v[i]]++;
    			sum[lca(u[i] , v[i])] -= 2;
    		}
    	}
    	for(re int i = n ; i >= 0 ; i--) 
    		sum[f[id[i]][0]] += sum[id[i]] ;
    	for(re int i = 1 ; i <= n ; ++i)
    		if(sum[i] >= cnt && maxx - value[i] <= k)
    			return true;
    	return false;
    }
    
    int main(){
    	n = read() ; m = read(); 
    	for(re int i = 1 ; i <= n - 1 ; ++i){
    		a = read(); b = read(); t = read();
    		add(a , b , t);
    		add(b , a , t);
    	}
    	dfs(1 , 0);
    	int l = 0 , r = 0 ;
    	for(re int i = 1 ; i <= m ; ++i){
    		u[i] = read(); v[i] = read();
    		len[i] = dis[u[i]] + dis[v[i]] - 2 * dis[lca(u[i] , v[i])] ;
    		r = max(r , len[i]);
    	}
    	while(l <= r) {
    		int mid = (l + r) >> 1;
    		if(check(mid)) {
    			ans = mid;
    			r = mid - 1 ;
    		}
    		else l = mid + 1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Java如何编写自动售票机程序
    install windows service
    redis SERVER INSTALL WINDOWS SERVICE
    上传文件
    This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.
    解决Uploadify上传控件加载导致的GET 404 Not Found问题
    OracleServiceORCL服务不见了怎么办
    Access to the temp directory is denied. Identity 'NT AUTHORITYNETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss
    MSSQL Server 2008 数据库安装失败
    数据库数据导出成XML文件
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/9929656.html
Copyright © 2011-2022 走看看