[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_('\n');
		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_('\n');
		}
	}
	flush(); return 0;
}
posted @ 2019-07-22 10:30  LinZhengmin  阅读(242)  评论(0编辑  收藏  举报

Contact with me