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;
    }
    
  • 相关阅读:
    IOS7笔记-10、多线程、滚动视图
    IOS7笔记-8、协议、block、动画
    IOS7笔记- 7、视图、绘制、手势识别
    IOS7笔记-6、控制器多态性、导航控制器、选项卡栏控制器
    IOS7笔记-5、视图控制器生命周期
    C# DevExpress之GridView同步滚动条记录方法
    C# 隐藏TabControl标签
    VC++ 如何识别系统语言类别
    我的免费空间网站
    慕课网-Java入门第一季-7-5 Java 中带参无返回值方法的使用
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/11224381.html
Copyright © 2011-2022 走看看