zoukankan      html  css  js  c++  java
  • icpc2019 香港 C. Constructing Ranches (点分治)

    题目链接:https://codeforces.com/gym/102452/problem/C

    (n) 条边能够形成多边形的结论是所有边之和大于最长的边

    于是点分治,维护每个点到根的路径上的点权和和点权最大值,统计满足 (sum[u]+sum[v]-a[rt]>2 imes max{mx[u], mx[v]}),的点对((u,v))的数量,考虑将所有点的 (sum)(mx) 排序,这样从小到大扫描时保证当前点 (u)(mx) 为最大值,然后树状数组统计满足 (sum[v] > 2*mx[u]-sum[u]+a[rt]) 的点 (v) 的数量,容斥即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 400010;
    const ll INF = 1e18+7;
    
    int T, n, m;
    ll a[maxn], ans;
    
    int h[maxn], cnt = 0;
    struct E{
    	int to, next;
    }e[maxn<<1];
    void add(int u, int v){
    	e[++cnt].to = v;
    	e[cnt].next = h[u];
    	h[u] = cnt;
    } 
    
    int rt, tot;
    int sz[maxn], son[maxn], vis[maxn], maxson;
    
    void getrt(int u, int par){
    	sz[u] = 1; son[u] = 0;
    	for(int i = h[u] ; i != -1 ; i = e[i].next){
    		int v = e[i].to;
    		if(vis[v] || v == par) continue;
    		getrt(v, u);
    		sz[u] += sz[v];
    		son[u] = max(son[u], sz[v]);
    	}
    	son[u] = max(son[u], tot - sz[u]);
    	if(son[u] < maxson){
    		maxson = son[u];
    		rt = u;
    	}
    }
    
    struct Node{
    	int id;
    	ll dis, mx;
    	
    	bool operator < (const Node & x) const{
    		return mx < x.mx;
    	}
    }p[maxn];
    
    int num = 0;
    ll dis[maxn], mx[maxn], b[maxn];
    void getdis(int u, int par){
    	++num;
    	p[num].id = u, p[num].dis = dis[u], p[num].mx = mx[u];
    	b[num] = dis[u];
    	for(int i = h[u] ; i != -1 ; i = e[i].next){
    		int v = e[i].to;
    		if(vis[v] || v == par) continue;
    		dis[v] = dis[u] + a[v];
    		mx[v] = max(mx[u], a[v]);
    		getdis(v, u);
    	}
    }
    
    int q;
    ll c[maxn];
    
    void ad(int x, int val){
    	for(int i = x ; i <= 200000 ; i += i&(-i)){
    		c[i] += val;
    	}
    }
    
    ll sum(int x){
    	ll res = 0;
    	for(int i = x ; i ; i -= i & (-i)){
    		res += c[i];
    	}
    	return res;
    }
    
    void calc(int u){
    	num = 0;
    	dis[u] = a[u], mx[u] = a[u];
    	getdis(u, 0);
    
    	sort(p+1, p+1+num);
    
    	b[num+1] = INF;
    	sort(b+1, b+1+num+1);
    	q = unique(b+1, b+1+num+1)-b-1;
    	for(int i = 1 ; i <= num ; ++i) {
    		p[i].dis = lower_bound(b+1, b+1+q, p[i].dis)-b;
    	}
    	
    	for(int i = 1 ; i <= num ; ++i){
    		int pos = upper_bound(b+1, b+1+q, 2ll*p[i].mx-b[p[i].dis]+a[u])-b;
    		ans += sum(q) - sum(pos-1);
    		ad(p[i].dis, 1);
    	}
    	
    	for(int i = 1 ; i <= num ; ++i){
    		ad(p[i].dis, -1);
    	}
    	
    	for(int i = h[u] ; i != -1 ; i = e[i].next){
    		int v = e[i].to;
    		if(vis[v]) continue;
    
    		num = 0;
    		dis[v] = a[u]+a[v];
    		mx[v] = max(a[u], a[v]);
    		getdis(v, u);
    		
    		sort(p+1, p+1+num);
    		
    		b[num+1] = INF;
    		sort(b+1, b+1+num+1);
    		q = unique(b+1, b+1+num+1)-b-1;
    		
    		for(int j = 1 ; j <= num ; ++j) {
    			p[j].dis = lower_bound(b+1, b+1+q, p[j].dis)-b;
    		}
    		for(int j = 1 ; j <= num ; ++j){
    			int pos = upper_bound(b+1, b+1+q, 2ll*p[j].mx-b[p[j].dis]+a[u])-b;
    			ans -= sum(q) - sum(pos-1);
    			ad(p[j].dis, 1);
    		} 
    		
    		for(int j = 1 ; j <= num ; ++j){
    			ad(p[j].dis, -1);
    		}
    	}
    }
    
    void divi(int u){
    	calc(u);
    	vis[u] = 1;
    	
    	for(int i = h[u] ; i != -1 ; i = e[i].next){
    		int v = e[i].to;
    		if(vis[v]) continue;
    		maxson = 1000000007, tot = sz[v];
    		getrt(v, u);
    		divi(rt);
    	}
    }
    
    void solve(){
    	maxson = 1000000007, tot = n;
    	getrt(1, 0);
    	divi(rt);
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	T = read();
    	while(T--){
    		ans = 0;
    		memset(h, -1, sizeof(h));
    		n = read();
    		for(int i = 1 ; i <= n ; ++i) vis[i] = 0;
    		for(int i = 1 ; i <= n ; ++i) a[i] = read();
    		int u, v;
    		for(int i = 1 ; i < n ; ++i){
    			u = read(), v = read();
    			add(u, v); add(v, u);
    		}
    		
    		solve();
    		
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    克如斯卡尔 P1546
    真正的spfa
    第四课 最小生成树 要点
    关于vscode中nullptr未定义
    cmake学习笔记
    python学习笔记
    (BFS 图的遍历) 2906. kotori和迷宫
    (图论基础题) leetcode 997. Find the Town Judge
    (BFS DFS 并查集) leetcode 547. Friend Circles
    (BFS DFS 图的遍历) leetcode 841. Keys and Rooms
  • 原文地址:https://www.cnblogs.com/tuchen/p/15308775.html
Copyright © 2011-2022 走看看