zoukankan      html  css  js  c++  java
  • [ZOJ3649]Social Net 题解

    前言

    这道题目珂以说是很毒瘤了。

    题解

    首先克鲁斯卡尔求最大生成树,输出边权和。
    倍增维护四个值:
      链上最大值/最小值
      链向上/向下最大差值
    当然祖先是肯定要维护的。
    然后把一条链经LCA分成两半。
    分向上向下按照之前维护的值动态计算。
    最后注意多组数据的维护(清空数组,边数之类的变量)。

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int LOG_N = 15;
    const int INF = 1 << 28;
    
    namespace fast_IO{
        const int OUT_LEN = 10000000;
        char obuf[OUT_LEN], *oh = obuf, *lastout = obuf + OUT_LEN - 1;
        inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
        inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
        void write(int x){
            if (x < 0) putchar_('-'), x = -x;
            if (x > 9) write(x / 10);
            putchar_(x % 10 + '0');
        }
    }
    
    using namespace fast_IO;
    
    struct Node{
    	int anc;
    	int min, max;
    	int udif, ddif;
    } f[30005][LOG_N + 1];
    
    struct PreEdge{
    	int u, v, w;
    } pre_edge[50005];
    
    bool operator < (const PreEdge &a, const PreEdge &b){
    	return a.w > b.w;
    }
    
    struct Edge{
    	int to, val, next;
    } edges[60005];
    
    int head[30005], edge_num;
    
    inline void addEdge(int from, int to, int val){
    	edges[++edge_num] = (Edge){to, val, head[from]};
    	head[from] = edge_num;
    }
    
    int n;
    int c[30005];
    int fa[30005];
    
    int getF(int u){
    	if (fa[u] == u) return u;
    	return (fa[u] = getF(fa[u]));
    }
    
    int deep[30005];
    
    void preDFS(int u, int fat){
    	deep[u] = deep[fat] + 1;
    	f[u][0] = (Node){fat, c[fat], c[fat], -INF, -INF};
    	for (int i = 1; i <= LOG_N; ++i)
    		f[u][i] = (Node){
    			f[f[u][i - 1].anc][i - 1].anc,
    			min(f[u][i - 1].min, f[f[u][i - 1].anc][i - 1].min), max(f[u][i - 1].max, f[f[u][i - 1].anc][i - 1].max),
    			max(max(f[u][i - 1].udif, f[f[u][i - 1].anc][i - 1].udif), f[u][i - 1].max - f[f[u][i - 1].anc][i - 1].min),
    			max(max(f[u][i - 1].ddif, f[f[u][i - 1].anc][i - 1].ddif), f[f[u][i - 1].anc][i - 1].max - f[u][i - 1].min)
    		};
    	for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
    		int v = edges[c_e].to;
    		if (v != fat)
    			preDFS(v, u);
    	}
    }
    
    int LCA(int x, int y){
    	if (deep[x] < deep[y]) swap(x, y);
    	for (int i = LOG_N; ~i; --i)
    		if (deep[f[x][i].anc] >= deep[y]) x = f[x][i].anc;
    	if (x == y) return x;
    	for (int i = LOG_N; ~i; --i)
    		if (f[x][i].anc != f[y][i].anc) x = f[x][i].anc, y = f[y][i].anc;
    	return f[x][0].anc;
    }
    
    int ans_min, ans_max;
    int ans;
    
    void getUp(int x, int y){
    	ans_max = max(ans_max, c[x]);
    	for (int i = LOG_N; i >= 0; --i){
    		if (deep[f[x][i].anc] > deep[y]){
    			ans = max(ans, ans_max - f[x][i].min);
    			ans_max = max(ans_max, f[x][i].max);
    			ans = max(ans, f[x][i].udif);
    			x = f[x][i].anc;
    		}
    	}
    }
    
    void getDown(int x, int y){
    	ans_min = min(ans_min, c[x]);
    	for (int i = LOG_N; i >= 0; --i){
    		if (deep[f[x][i].anc] >= deep[y]){
    			ans = max(ans, f[x][i].max - ans_min);
    			ans_min = min(ans_min, f[x][i].min);
    			ans = max(ans, f[x][i].ddif);
    			x = f[x][i].anc;
    		}
    	}
    }
    
    inline void init(){
    	memset(c, 0, sizeof(c));
    	memset(f, 0, sizeof(f));
    	memset(edges, 0, sizeof(edges));
    	memset(pre_edge, 0, sizeof(pre_edge));
    	memset(deep, 0, sizeof(deep));
    	memset(head, 0, sizeof(head));
    	edge_num = 0;
    }
    
    int main(){
    	while (scanf("%d", &n) == 1 && n){
    		init();
    		for (int i = 1; i <= n; ++i) scanf("%d", &c[i]), fa[i] = i;
    		int m; scanf("%d", &m);
    		for (int i = 0; i < m; ++i){
    			int u, v, w; scanf("%d %d %d", &u, &v, &w);
    			pre_edge[i] = (PreEdge){u, v, w};
    		}
    		sort(pre_edge, pre_edge + m); ans = 0;
    		for (int i = 0, j = 0; i < m; ++i){
    			int rtu = getF(pre_edge[i].u), rtv = getF(pre_edge[i].v);
    			if (rtu != rtv){
    				fa[rtu] = rtv; ans += pre_edge[i].w;
    				addEdge(pre_edge[i].u, pre_edge[i].v, pre_edge[i].w);
    				addEdge(pre_edge[i].v, pre_edge[i].u, pre_edge[i].w);
    				++j;
    				if (j == n - 1) break;
    			}
    		}
    		write(ans), putchar_('
    ');
    		preDFS(1, 1);
    		int q; scanf("%d", &q);
    		while (q--){
    			int x, y; scanf("%d %d", &x, &y);
    			int xylca = LCA(x, y);
    			ans = 0, ans_min = INF, ans_max = -INF;
    			getUp(y, xylca), getDown(x, xylca);
    			ans = max(ans, ans_max - ans_min);
    			write(ans); putchar_('
    ');
    		}
    	}
    	flush(); return 0;
    }
    
  • 相关阅读:
    js对象数组(JSON) 根据某个共同字段 分组
    一个 函数 用来转化esSearch 的range 条件
    关于 vuex 报错 Do not mutate vuex store state outside mutation handlers.
    android listview 重用view导致的选择混乱问题
    android SDK和ADT的更新
    Android中adb push和adb install的使用区别
    pycharm中添加扩展工具pylint
    su Authentication failure解决
    Putty以及adb网络调试
    有关android源码编译的几个问题
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/11224381.html
Copyright © 2011-2022 走看看