BZOJ 2843: 极地旅行社 & BZOJ 1180: [CROATIAN2009]OTOCI

刷一赠一系列!

Description

给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作: 1、bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。 2、penguins A X:将结点A对应的权值wA修改为X。 3、excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。给出q个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。

Input

第一行包含一个整数n(1<=n<=30000),表示节点的数目。第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。第三行包含一个整数q(1<=n<=300000),表示操作的数目。以下q行,每行包含一个操作,操作的类别见题目描述。任意时刻每个节点对应的权值都是1到1000的整数。

Output

输出所有bridge操作和excursion操作对应的输出,每个一行。

Sample Input

5

4 2 4 5 6

10

excursion 1 1

excursion 1 2

bridge 1 2

excursion 1 2

bridge 3 4

bridge 3 5

excursion 4 5

bridge 1 3

excursion 2 4

excursion 2 5

Sample Output

4

impossible

yes

6

yes

yes

15

yes

15

16

Solution

LCT模板题。然而我还是忘了要在Find root前access+splay,和access的时候pushup()!

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>
#include <cstdio>
using namespace std;
const int INF = 1<<30;
const int maxn = 30233;
typedef long long LL;
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; '0' > c || c > '9'; c = getchar()) if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
char getop() {
	char c;
	for (c = getchar(); 'a' > c || c > 'z'; c = getchar());
	return c;
}
int n,m;
int rev[maxn],sum[maxn],c[maxn][2],p[maxn],fa[maxn];
void pd(int x) {
	if (rev[x]) {
		rev[c[x][0]]^=1;rev[c[x][1]]^=1;rev[x]=0;
		swap(c[x][0],c[x][1]);
	}
}
void pu(int x) {
	sum[x] = sum[c[x][0]]+sum[c[x][1]]+p[x];
}
bool isroot(int x){
	return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
int ws(int x) {
	return c[fa[x]][1]==x;
}
void rotate(int x) {
	int y=fa[x],z=fa[y],a=ws(x),b=!a;
	if(!isroot(y)){
		if(y==c[z][0]) c[z][0]=x;
		else c[z][1]=x;
	}
	fa[x]=z;fa[y]=x;fa[c[x][b]]=y;
	c[y][a]=c[x][b];c[x][b]=y;
	pu(y); pu(x);
}
int st[maxn];
void splay(int x) {
	int tail = 1; st[1] = x;
	for (int i=x;!isroot(i);i=fa[i]) st[++tail]=fa[i];
	while(tail) pd(st[tail--]);
	while (!isroot(x)) {
		int y=fa[x],z=fa[y];
		if(!isroot(y)){
			if(c[y][0]==x^c[z][0]==y)rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
void access(int x){
	int y = 0;
	while(x) {
		splay(x);
		c[x][1]=y;
		pu(x); //Attention!
		y=x;x=fa[x];
	}
}
void mkrt(int x) {
	access(x); splay(x); rev[x] ^= 1;
}
void link(int u,int v) {
	mkrt(u);
	fa[u]=v;
	splay(u);
}
void cut(int u,int v) {
	mkrt(u);
	access(v);
	splay(v);
	fa[u]=0;
	c[v][0]=0;
}
int ask(int x, int y) {
	mkrt(x);
	access(y);
	splay(y);
	return sum[y];// 
}
void change(int pos, int x) {
	mkrt(pos);
	p[pos]=x;
	pu(pos);
}
int findrt(int x) {
	access(x); splay(x); //Forgot
	while (c[x][0]) x = c[x][0];
	splay(x);
	return x;
}
int main() {
	n = getint();int x;
	for (int i = 1; i <= n; ++i) {
		x=getint();
		p[i]=sum[i]=x;
	}
	m=getint();
	char op; int y;
	while(m--) {
		op = getop();
		x = getint(); y = getint();
		if (op == 'b') {
			if (findrt(x)==findrt(y)) {
				printf("no\n");
			} else {
				printf("yes\n");
				link(x, y);
			}
			continue;
		}
		if (op == 'p'){
			change(x,y);
			continue;
		}
		if (findrt(x)!=findrt(y)) {
			printf("impossible\n");
		} else {
			printf("%d\n", ask(x,y));
		}
	}
	return 0;
}