zoukankan      html  css  js  c++  java
  • [NOIp2015][二分][LCA] 运输计划

    题面

    // 二分一个路径长,并要求所有长度大于该
    // 长度的路径经过同一条边,且该边的长度
    // 比每条路径的长度与二分路径长度差值大,
    // 即为所求答案。
    
    // 差分数组用于确定是否每条路径都经过该边
    
    # include <iostream>
    # include <cstdio>
    # include <cstring>
    # define MAXN 300005
    
    struct Edge{
    	int v, w, next;
    }e[MAXN<<1];
    struct Query{
    	int x, y;
    	int lca, dis;
    }q[MAXN];
    struct node{
    	int fa, hSon, dep, top, siz, dis;
    }nd[MAXN];
    int hd[MAXN], cntE, d[MAXN], co[MAXN]; // d 是差分数组
    int n, m;int seg[MAXN], cntS;
    int L, R;
    
    template<typename T>
    void rd(T & x);
    void AddE(int u, int v, int w);
    void PreDFS(int now, int fa);
    void SegDFS(int now, int top);
    int  GetLCA(int x, int y);
    bool chk(int val);
    
    int main(){
    	rd<int>(n), rd<int>(m);
    
    	for(int i = 1, u, v, w; i <= n-1; i++){
    		rd<int>(u), rd<int>(v), rd<int>(w);
    		AddE(u, v, w); AddE(v, u, w);
    		L = std::max(L, w);
    	}
    
    	PreDFS(1, 0);
    	SegDFS(1, 1);
    
    	for(int i = 1; i <= m; i++){
    		rd<int>(q[i].x), rd<int>(q[i].y);
    		q[i].lca = GetLCA(q[i].x, q[i].y);
    		q[i].dis = nd[q[i].x].dis + nd[q[i].y].dis - (nd[q[i].lca].dis*2);
    		R = std::max(R, q[i].dis);
    	}
    
    	int l = R-L, r = R+1;
    	while(l < r){
    		int mid = (l + r) >> 1;
    		if(chk(mid)){
    			r = mid;
    		}
    		else{
    			l = mid+1;
    		}
    	}
    
    	printf("%d", l);
    
    	return 0;
    }
    
    bool chk(int val){
    	memset(d, 0, sizeof(d));
    	
    	int cntSu = 0;
    	for(int i = 1; i <= m; i++){
    		if(q[i].dis > val){
    			d[q[i].x]++, d[q[i].y]++, d[q[i].lca] -= 2;
    			cntSu++;
    		}
    	}
    
    	for(int i = n; i >= 1; i--){
    		d[nd[seg[i]].fa] += d[seg[i]];
    		if(co[seg[i]] >= R - val && d[seg[i]] == cntSu){
    			return 1;
    		}
    	}
    
    	return 0;
    }
    
    int  GetLCA(int x, int y){
    	while(nd[x].top != nd[y].top){
    		if(nd[nd[x].top].dep < nd[nd[y].top].dep){
    			std::swap(x, y);
    		}
    		x = nd[nd[x].top].fa;
    	}
    	return nd[x].dep < nd[y].dep ? x : y;
    }
    
    void SegDFS(int now, int top){
    	nd[now].top = top;
    
    	if(!nd[now].hSon){
    		return;
    	}
    
    	SegDFS(nd[now].hSon, top);
    
    	for(int i = hd[now]; i; i = e[i].next){
    		if(e[i].v == nd[now].fa || e[i].v == nd[now].hSon){
    			continue;
    		}
    
    		SegDFS(e[i].v, e[i].v);
    	}
    }
    
    void PreDFS(int now, int fa){
    	nd[now].fa = fa, nd[now].dep = nd[fa].dep + 1;
    	nd[now].siz = 1; seg[++cntS] = now;
    
    	for(int i = hd[now]; i; i = e[i].next){
    		if(e[i].v == fa){
    			continue;
    		}
    
    		co[e[i].v] = e[i].w;
    		nd[e[i].v].dis = nd[now].dis + e[i].w; // 注意这句话的位置
    
    		PreDFS(e[i].v, now);
    
    		nd[now].siz += nd[e[i].v].siz;
    		
    		if(nd[e[i].v].siz > nd[nd[now].hSon].siz){
    			nd[now].hSon = e[i].v;
    		}
    	}
    }
    
    void AddE(int u, int v, int w){
    	e[++cntE].v = v, e[cntE].next = hd[u], hd[u] = cntE;
    	e[cntE].w = w;
    }
    
    template<typename T>
    void rd(T & x){
    	x = 0; T fl = 1;
    	int ch = getchar();
    	for(	;!isdigit(ch); ch = getchar()){
    		if(ch == '-'){
    			fl = -1;
    		}
    	}
    	for(	; isdigit(ch); ch = getchar()){
    		x = x * 10 + ch - '0';
    	}
    	x *= fl;
    }
    
  • 相关阅读:
    垃圾回收机制,正则模块
    日常模块
    文件路径带有字符串的处理方法
    QT进制之间的相互转换
    4-7 selectors模块
    4-5 异步IO模型
    4-4 多路复用IO模型
    4-3 非阻塞IO
    4-2 阻塞IO
    4-1 IO模型介绍
  • 原文地址:https://www.cnblogs.com/Foggy-Forest/p/13531309.html
Copyright © 2011-2022 走看看