NOI模拟(10.29)T1 管道

管道

题目背景:

10.29 NOI模拟T1

分析:倍增 or lctor 链剖 + 线段树 or 链剖 + st or···

 

我终于明白了,先入为主是在作死······拿到这道题,第一反应最小生成树,然后要改边,这个不是lct裸题吗,然后一发lct就上去了······然后后来才听说,貌似这个题把最小生成树建出来是不是就很稳了······不管链剖或者倍增好像都能直接找到路径最大值····然后check一下就好了·····最后只好安慰自己复杂度是一样的······最后还是跑过去了,最慢的点0.92s····

Source:

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 500000 + 10;

struct edges {
	int u, v, w, id;
	edges(int u = 0, int v = 0, int w = 0, int id = 0) : 
		u(u), v(v), w(w), id(id) {}
	inline bool operator < (const edges &a) const {
		return w < a.w;
	}
} e[MAXN];

int w[MAXN], ans[MAXN];

struct node *null;
struct node {
	node *c[2], *fa, *pa;
	bool rev;
	int max, val;
	
	node(int val = 0) : fa(null), pa(null), rev(false), max(val), val(val) {
		c[0] = c[1] = null;
	}
	
	inline int relation() {
		return (this == fa->c[1]);
	}
	
	inline void reverse() {
		if (this == null) return ;
		rev ^= 1, std::swap(c[0], c[1]);
	}
	
	inline void push_down() {
		if (this == null) return ;
		if (rev) c[0]->reverse(), c[1]->reverse(), rev ^= 1;
	}
	
	inline void maintain() {
		if (this == null) return ;
		max = val;
		if (w[c[0]->max] > w[max]) max = c[0]->max;
		if (w[c[1]->max] > w[max]) max = c[1]->max;
	}
	
	inline void rotate() {
		push_down();
		pa = fa->pa, fa->pa = null;
		node *old_fa = fa;
		int x = relation();
		if (old_fa->fa != null) old_fa->fa->c[old_fa->relation()] = this;
		old_fa->c[x] = c[x ^ 1], fa = old_fa->fa;
		if (c[x ^ 1] != null) c[x ^ 1]->fa = old_fa;
		c[x ^ 1] = old_fa, old_fa->fa = this, old_fa->maintain(), maintain();
	}
	
	inline void splay(node *target = null) {
		while (fa != target) {
			fa->fa->push_down(), fa->push_down();
			if (fa->fa == target) fa->push_down(), rotate();
			else if (fa->relation() == relation()) fa->rotate(), rotate();
			else rotate(), rotate();
		}
		push_down();
	}
	
	inline void expose() {
		splay();
		if (c[1] != null) 
			c[1]->fa = null, c[1]->pa = this, c[1] = null, maintain();
	}
	
	inline bool splice() {
		expose();
		if (pa == null) return false;
		pa->expose(), pa->c[1] = this, fa = pa, pa = null, fa->maintain();
		return true;
	}
	
	inline void access() {
		expose();
		while (splice());
		splay();
	}
	
	inline void evert() {
		access(), reverse();
	}
} point[MAXN];

inline void link(node *u, node *v) {
	u->evert(), u->pa = v;
}

inline void cut(node *u, node *v) {
	u->evert(), v->access(), v->c[0] = null, u->fa = null, v->maintain();
}

inline node *find_root(node *u) {
	u->evert();
	for (; u->push_down(), u->c[0] != null; u = u->c[0]);
	return u->splay(), u;
}

inline int query_max(node *u, node *v) {
	return u->evert(), v->access(), v->max;
}

int n, m;
inline void read_in() {
	R(n), R(m);
	for (int i = 1; i <= m; ++i) 
		R(e[i].u), R(e[i].v), R(e[i].w), e[i].id = i, w[i] = e[i].w;
}

int father[MAXN];

inline int get_father(int x) {
	return (father[x] == x) ? x : (father[x] = get_father(father[x])); 
}

inline void solve() {
	long long mst = 0;
	std::sort(e + 1, e + m + 1);
	null = &point[0], null->c[0] = null->c[1] = null->pa = null->fa = null;
	null->val = null->max = 0;
	for (int i = 1; i <= n; ++i) father[i] = i, point[i] = node(0);
	for (int i = 1; i <= m; ++i) {
		point[i + n] = node(e[i].id);
		int u = e[i].u, v = e[i].v, fa1 = get_father(u), fa2 = get_father(v);
		if (fa1 != fa2) {
			mst += e[i].w, ans[e[i].id] = 0, father[fa1] = fa2;
			link(&point[u], &point[i + n]), link(&point[v], &point[i + n]);
		} else ans[e[i].id] = e[i].w - w[query_max(&point[u], &point[v])];
	}
	for (int i = 1; i <= m; ++i) W(mst + (long long)ans[i]), write_char('\n');
}

int main() {
//	freopen("pipe.in", "r", stdin);
//	freopen("pipe.out", "w", stdout);
	read_in();
	solve();
	flush();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值