【BZOJ 2157】旅游

再水一道模板题,明天就要出发去参加二轮省选了赶紧复习复习模板。

链剖模板题,可是写链剖太麻烦了,还是写lct吧。

但这个lct比较麻烦了,因为边权有正有负,要统计最大值和最小值,这样点权赋为什么值都会妨碍统计。

想了半天,后来发现自己脑抽了,统计的时候特判一下当前点是点还是边不就可以了吗?

裸的模板题调了好久啊,因为后来往原先错误的程序加上上述特判时总是漏这漏那,以后一定要认真思考每个细节确保无误后再开始写代码,这样脑子里有一个清晰的框架,写起来更快,而且不容易出错,大大节省了调试的时间。切忌边想边写!!!这样写到最后会有很多bug,而且对于程序的每个函数的作用会比较模糊。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20003;
const int inf = 0x7fffffff;
void read(int &k) {
	k = 0; int fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = (k << 1) + (k << 3) + c - '0';
	k = k * fh;
}

struct node *null;
struct node {
	node *ch[2], *fa;
	int d, mx, mn, sum;
	bool edge;
	short rev, change;
	bool pl() {return fa->ch[1] == this;}
	void setc(node *r, bool c) {ch[c] = r; r->fa = this;}
	bool check() {return fa == null || (fa->ch[0] != this && fa->ch[1] != this);}
	void upd() {if (this == null) return; sum = -sum; d = -d; swap(mx, mn); mx = -mx; mn = -mn;}
	void push() {
		if (rev) {rev = 0; swap(ch[0], ch[1]); ch[0]->rev ^= 1; ch[1]->rev ^= 1;}
		if (change) {
			change = 0;
			ch[0]->change ^= 1; ch[1]->change ^= 1;
			ch[0]->upd(); ch[1]->upd();
		}
	}
	void count() {
		sum = ch[0]->sum + ch[1]->sum;
		mx = max(ch[0]->mx, ch[1]->mx); mn = min(ch[0]->mn, ch[1]->mn);
		if (edge) mx = max(mx, d), mn = min(mn, d), sum += d;
	}
} pool[N + N], *p[N], *E[N];

namespace LCT {
	void rotate(node *r) {
		node *f = r->fa; bool c = r->pl();
		if (f->check()) r->fa = f->fa;
		else f->fa->setc(r, f->pl());
		f->setc(r->ch[!c], c);
		r->setc(f, !c);
		f->count();
	}
	void update(node *r) {if (!r->check()) update(r->fa); r->push();};
	void splay(node *r) {
		update(r);
		for(; !r->check(); rotate(r))
			if (!r->fa->check()) rotate(r->pl() == r->fa->pl() ? r->fa : r);
		r->count();
	}
	node *access(node *r) {
		node *y = null;
		for(; r != null; y = r, r = r->fa)
			splay(r), r->ch[1] = y;
		return y;
	}
	void changert(node *r) {access(r)->rev ^= 1; splay(r);}
	void link(node *r, node *t) {changert(r); r->fa = t;}
	int tot = 0;
	node *newnode(int num, bool flag) {
		node *t = &pool[++tot];
		t->ch[0] = t->ch[1] = t->fa = null;
		t->d = t->sum = num;
		t->rev = t->change = 0;
		t->edge = flag;
		if (flag) t->mx = t->mn = num;
		else t->mx = -inf, t->mn = inf;
		return t;
	}
	void Build(int n) {
		null = new node;
		null->ch[0] = null->ch[1] = null->fa = null;
		null->mx = -inf; null->mn = inf;
		null->rev = null->change = null->edge = null->d = null->sum = 0;
		for(int i = 0; i < n; ++i) p[i] = newnode(0, 0);
	}
}

int n, m;
int main() {
	read(n);
	LCT::Build(n);
	int u, v, e, x, y;
	for(int i = 1; i < n; ++i) {
		read(u); read(v); read(e);
		E[i] = LCT::newnode(e, 1);
		LCT::link(p[u], E[i]); LCT::link(p[v], E[i]);
	}
	read(m);
	char c[3];
	for(int i = 1; i <= m; ++i) {
		scanf("%s", c); read(u); read(v);
		switch (c[0]) {
			case 'C':
				LCT::splay(E[u]);
				E[u]->d = v; E[u]->count();
			break;
			case 'N':
				LCT::changert(p[u]); LCT::access(p[v]); LCT::splay(p[v]);
				p[v]->upd(); p[v]->change ^= 1;
			break;
			case 'S':
				LCT::changert(p[u]); LCT::access(p[v]); LCT::splay(p[v]);
				printf("%d\n", p[v]->sum);
			break;
			case 'M':
				LCT::changert(p[u]); LCT::access(p[v]); LCT::splay(p[v]);
				if (c[1] == 'A') printf("%d\n", p[v]->mx);
				else printf("%d\n", p[v]->mn);
			break;
		}
	}
	return 0;
}

SDOI 2016 Round2 Day-1 Bless All,祝CreationAugust,TA,morestep,Vampire,Sunshine,Lcomyn,Rivendell学长们和fye学姐都进队!

posted @ 2016-05-12 20:37  abclzr  阅读(215)  评论(0编辑  收藏  举报