【BZOJ 3083】遥远的国度

这道题很简单的连剖+分类讨论,但是SDOI Round2要来了,不会手动栈怎么办呢?只好用一下这道题练习一下手动栈了,结果调了一天多QwQ

链剖的第一个dfs用bfs水过就行,但是我自以为是地把倍增写错了,坑了好久啊QAQ

这道题因为要询问子树,连剖的第二个dfs就不能再用bfs水过了,只能强行手动栈。

一开始拍小数据拍出了好多错,改过来后拍了无数组极限数据也拍不出来,因为构造的极限数据太弱了(偷懒构造u<v)根本无法暴露倍增的漏洞啊!!!

手残错误毁一生,写代码时不要自以为是。希望SD省选能够给我们一个更好的编程环境和评测环境(NOILinux恐怕是奢望吧)

#include<stack>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100003;
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 {int nxt, to;} E[N << 1];
int n, m, point[N], cnt = 0, pos[N], wt[N], deep[N];
int lazy[N * 8], mn[N * 8], top[N], sz[N], f[N][18], root, a[N], son[N];

void ins(int x, int y) {E[++cnt] = (node) {point[x], y}; point[x] = cnt;}
stack <int> S;
int qu[N];
void _() {
	int p = 0, q = 1; qu[1] = 1;
	while (p != q) {
		int u = qu[++p];
		for(int tmp = point[u]; tmp; tmp = E[tmp].nxt)
			if (E[tmp].to != f[u][0])
				f[E[tmp].to][0] = u, deep[E[tmp].to] = deep[u] + 1, qu[++q] = E[tmp].to;
	}
	for(int i = q; i >= 1; --i) {
		int u = qu[i], fa = f[u][0];
		++sz[u];
		sz[fa] += sz[u];
		if (sz[u] > sz[son[fa]]) son[fa] = u;
	}
	for(int j = 1; j <= 17; ++j)
		for(int i = 1; i <= n; ++i)
			f[i][j] = f[f[i][j - 1]][j - 1];
}
void __() {
	top[1] = 1; cnt = 0;
	S.push(1);
	while (!S.empty()) {
		int u = S.top(); S.pop();
		pos[++cnt] = u; wt[u] = cnt;
		for(int tmp = point[u]; tmp; tmp = E[tmp].nxt)
			if (E[tmp].to != f[u][0] && E[tmp].to != son[u])
				top[E[tmp].to] = E[tmp].to, S.push(E[tmp].to);
		if (son[u]) {top[son[u]] = top[u]; S.push(son[u]);}
	}
}
/* 下面是正确的人工栈模板,完美模拟dfs,但是我学会它不到5小时我就用bfs把它淘汰了
void _() {
	S.push(Data(1, point[1]));
	sz[1] = 1;
	while (!S.empty()) {
		int x = S.top().x, y = S.top().y; S.pop();
		if (y) {
			S.push(Data(x, E[y].nxt));
			int v = E[y].to;
			if (v != f[x][0]) {
				f[v][0] = x;
				sz[v] = 1;
				deep[v] = deep[x] + 1;
				for(int i = 1; i <= 17; ++i) {f[v][i] = f[f[v][i - 1]][i - 1]; if (f[v][i] == 0) break;}
				S.push(Data(v, point[v]));
			}
		} else {
			if (!S.empty()) {
				sz[S.top().x] += sz[x];
				if (sz[x] > sz[son[S.top().x]]) son[S.top().x] = x;
			}
		}
	}
}*/

void pushdown(int rt) {
	if (lazy[rt]) {
		mn[rt << 1] = mn[rt << 1 | 1] = lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
		lazy[rt] = 0;
	}
}
void pushup(int rt) {mn[rt] = min(mn[rt << 1], mn[rt << 1 | 1]);}
void Build(int rt, int l, int r) {
	if (l == r) {mn[rt] = a[pos[l]]; mn[rt << 1] = mn[rt << 1 | 1] = inf; return;}
	int mid = (l + r) >> 1;
	Build(rt << 1, l, mid);
	Build(rt << 1 | 1, mid + 1, r);
	pushup(rt);
}
void add(int rt, int l, int r, int L, int R, int x) {
	if (L <= l && r <= R) {lazy[rt] = x; mn[rt] = x; return;}
	int mid = (l + r) >> 1;
	pushdown(rt);
	if (L <= mid) add(rt << 1, l, mid, L, R, x);
	if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, x);
	pushup(rt);
}
void Add(int x, int y, int z) {
	for(; top[x] != top[y]; x = f[top[x]][0]) {
		if (deep[top[x]] < deep[top[y]]) swap(x, y);
		add(1, 1, n, wt[top[x]], wt[x], z);
	}
	if (deep[x] < deep[y]) swap(x, y);
	add(1, 1, n, wt[y], wt[x], z);
}
int QQ(int rt, int l, int r, int L, int R) {
	if (L <= l && r <= R) return mn[rt];
	int mid = (l + r) >> 1, s = inf;
	pushdown(rt);
	if (L <= mid) s = min(s, QQ(rt << 1, l, mid, L, R));
	if (R > mid) s = min(s, QQ(rt << 1 | 1, mid + 1, r, L, R));
	return s;
}
int Q(int L, int R) {
	if (L > n || R < 1 || L > R) return inf;
	return QQ(1, 1, n, L, R);
}

int lower;
int LCA(int x, int y) {
	if (deep[x] < deep[y]) return 1;
	for(int i = 16; i >= 0; --i) if (deep[f[x][i]] > deep[y]) x = f[x][i];
	lower = x;
	return f[x][0] != y;
}

int main() {
	read(n); read(m);
	int u, v, op, x;
	for(int i = 1; i < n; ++i) {
		read(u); read(v);
		ins(u, v); ins(v, u);
	}

	_();
	__();

	for(int i = 1; i <= n; ++i) read(a[i]);

	Build(1, 1, n);

	read(root);
	for(int i = 1; i <= m; ++i) {
		read(op);
		switch (op) {
			case 1:
				read(root);
			break;
			case 2:
				read(u); read(v); read(x);
				Add(u, v, x);
			break;
			case 3:
				read(u);
				if (root == u)
					printf("%d\n", Q(1, n));
				else
					if (LCA(root, u)) {
						printf("%d\n", Q(wt[u], wt[u] + sz[u] - 1));
					} else {
						v = min(Q(1, wt[lower] - 1), Q(wt[lower] + sz[lower], n));
						printf("%d\n", v);
					}
			break;
		}
	}

	return 0;
}

注释掉了能够完美模拟dfs但并没有什么用的手动栈= =

时间: 2025-01-04 04:51:51

【BZOJ 3083】遥远的国度的相关文章

BZOJ 3083 遥远的国度 树链剖分

3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连

BZOJ 3083 遥远的国度 树链剖分+线段树

有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<string> #include<iomanip> #include<a

BZOJ 3083 遥远的国度

链剖水题. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 100500 #define maxe 200500 #define inf 2147483647 using namespace std; int n,m,type,x,y,z,val[maxv],id=1,g[maxv],nume=0; int w[maxv],fw[ma

bzoj 3083 树链剖分

首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区间,后者询问区间的补集. /************************************************************** Problem: 3083 User: BLADEVIL Language: C++ Result: Accepted Time:6412 ms

【BZOJ】【3083】遥远的国度

树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果root在x的子树中(以1为根dfs的时候),那么现在x的子树就变成了整个dfs序中,除去含有root的那个子树的剩下的部分,画个图大概就是这样:(红色部分为现在的子树) 我们发现,这种子树由于换根而产生变化的情况,仅当在以1为根时的树中,x是new_root的祖先时发生,那么我们判断这种情况是否发生只需

bzoj 1000+AC

1500 [NOI2005]维修数列   5333 16036 1010 [HNOI2008]玩具装箱toy   5205 12140 2049 [Sdoi2008]Cave 洞穴勘测   4992 10282 1008 [HNOI2008]越狱   4820 11120 1503 [NOI2004]郁闷的出纳员   4629 12915 1208 [HNOI2004]宠物收养所   4216 10462 1026 [SCOI2009]windy数   4169 9168 1003 [ZJOI2

数据结构&#183;树链剖分+LCT

于是两个一起搞了... 怎么说,写的是P党风格的C++,短也不会短到哪里去,跑起来也不快,常数大成狗OTL BZOJ 1036 树链的经典题吧,点修改+路经询问 [Code] BZOJ 2243 路径修改+路径询问 [Code] BZOJ 3083 路径修改+子树询问(根可变),这道题要用树链剖分求DFS序中某一段区间的值(DFS序可查子树,链剖可修改路径,两者相结合就行了) [Code] BZOJ 2049 用LCT维护森林形态 [Code] BZOJ 2631 路径修改+路径询问+形态可变

一些数据结构题

树上的操作 3282 Tree 删边, 连边, 单点修改, 询问路径异或和. 1984: 月下“毛景树” 路径覆盖, 路径增加, 询问路径 max 简单树剖 3306: 树 要支持 换根, 修改点权,  查询子树最小值 不换根就是简单的dfs序线段树, 换根的话只需要知道当前根与查询的点的关系:如果查询点是根的儿子, 那么直接询问就可以: 如果询问点是根, 那么输出sum: 否则根一定在查询点的某个子树中,所以这个时候我们要查询的是原树中除了这棵子树以外其它所有点的min, 而这可以用在线段树上

loj 139 树链剖分

题目大意: 给定一棵n个节点的树,初始时该树的根为1号节点,每个节点有一个给定的权值.下面依次进行m个操作,操作分为如下五种类型: 换根:将一个指定的节点设置为树的新根 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值 询问路径:询问某条路径上节点的权值和 询问子树:询问某个子树内节点的权值和 思路: 莫得思路 换根就完事了(讨论一下根是否在查询点的子树里) 1 #in