【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学姐都进队!

时间: 2024-10-09 07:16:04

【BZOJ 2157】旅游的相关文章

BZOJ 2157 旅游(动态树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2157 [题目大意] 支持修改边,链上查询最大值最小值总和,以及链上求相反数 [题解] 我们将边转化成点,直接用LCT可以处理以上操作 [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010; int n; co

BZOJ 2157 旅游(树链剖分+线段树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2157 [题目大意] 支持修改边,链上查询最大值最小值总和,以及链上求相反数 [题解] 树链剖分,然后线段树维护线段操作即可. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF=~0U>>1; const

bzoj 2157 旅游

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2157 明明是裸LCT板子-- 注意pshp的那个地方!原以为把0~n的mx.mn都赋好初值就能随便弄了,仔细想想要用的是val! 而且还是既用在max里又用在min里,故不能赋初值来怎样,应当分类讨论! 关于变成相反数的操作,原来也是打标记!而且标记的含义和线段树的一样,表示自己已经操作过.要给孩子操作.这样才能保证query的正确. 可是自己那种dfs来当即弄成相反数的做法为什么不行??

BZOJ 2157 旅游 树链剖分

题目大意:给出一棵树,支持以下操作:1.改变一条边的边权.2.将x到y路径的权值取反.3.查询x到y路径上最大值,最小值和权值和. 思路:好裸的链剖水题啊,唯一麻烦一点地是权值放在了边上,注意一下处理就没问题了.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

【BZOJ】2157: 旅游

http://www.lydsy.com/JudgeOnline/problem.php?id=2157 题解:裸lct不解释.. #include <bits/stdc++.h> using namespace std; struct node *null; struct node { node *c[2], *f; bool flag, rev, tag; int k, sum, mx, mn; bool d() { return f->c[1]==this; } void setc

AC日记——旅游 bzoj 2157

2157 思路: LCT: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 400005 #define INF 0x3f3f3f3f int n,val[maxn],sum[maxn],Max[maxn],Min[maxn],ch[maxn][2]; int rev[maxn],flag[maxn],f[maxn],top,st[maxn],m,cur[maxn],id; inline void in(int &a

bzoj 2157

链剖...这次的信息存在边上... 调了好久啊QAQ,没有看出连锁错误,对代码的敏感程度还是太差了,老是依赖debug(论NOIP为何会死得那么惨) 1 #include<bits/stdc++.h> 2 #define inc(i,l,r) for(int i=l;i<=r;i++) 3 #define dec(i,l,r) for(int i=l;i>=r;i--) 4 #define link(x) for(edge *j=h[x];j;j=j->next) 5 #de

BZOJ 2157 旅行(树链剖分码农题)

写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v经过的边的权值最小值. 基于边权的树链剖分,放在线段树上变成了区间维护问题了,线段树维护4个量min,max,sum,tag就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include