HDU 4010 Query on The Trees

题意:

一棵树  支持合并、分离、路径加权值、路径权值最大值

思路:

LCT入门题  也是我的第一道…  代码来源于kuangbin巨巨  我只是整理出自己的风格留作模版…

LCT比较好的入门资料是——《QTREE解法的一些研究》

LCT基本做法就是先dfs建树  然后根据输入做上述4个操作

对于合并  就是把u转到树根  然后接在v上

对于分离  就是把u转到splay的根  然后切断与左子树的连接

对于路径加值  就是求出lca  然后包含u和v的子树以及lca点进行加值

对于路径求最值  就是求出lca  然后和上面一样分三部分进行

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
#define N  300010
#define L(x) (ch[x][0])
#define R(x) (ch[x][1])

struct Edge {
	int v, next;
} ed[N * 2];
int head[N], tot;
int ch[N][2], pre[N], key[N], add[N], rev[N], Max[N];
bool rt[N];

void Update_Add(int u, int d) {
	if (!u)
		return;
	key[u] += d;
	add[u] += d;
	Max[u] += d;
}

void Update_Rev(int u) {
	if (!u)
		return;
	swap(L(u), R(u));
	rev[u] ^= 1;
}

void down(int u) {
	if (add[u]) {
		Update_Add(L(u), add[u]);
		Update_Add(R(u), add[u]);
		add[u] = 0;
	}
	if (rev[u]) {
		Update_Rev(L(u));
		Update_Rev(R(u));
		rev[u] = 0;
	}
}

void up(int u) {
	Max[u] = max(max(Max[L(u)], Max[R(u)]), key[u]);
}

//Rotate P Splay 一般不变
void Rotate(int x) {
	int y = pre[x], kind = ch[y][1] == x;
	ch[y][kind] = ch[x][!kind];
	pre[ch[y][kind]] = y;
	pre[x] = pre[y];
	pre[y] = x;
	ch[x][!kind] = y;
	if (rt[y])
		rt[y] = false, rt[x] = true;
	else
		ch[pre[x]][ch[pre[x]][1] == y] = x;
	up(y);
}

//P函数先将splay根结点到u的路径上所有的结点的标记逐级下放
void P(int u) {
	if (!rt[u])
		P(pre[u]);
	down(u);
}

void Splay(int u) {
	P(u);
	while (!rt[u]) {
		int fa = pre[u], ffa = pre[fa];
		if (rt[fa])
			Rotate(u);
		else if ((R(ffa) == fa) == (R(fa) == u))
			Rotate(fa), Rotate(u);
		else
			Rotate(u), Rotate(u);
	}
	up(u);
}

//将root到u的路径变成实边
int Access(int u) {
	int v = 0;
	for (; u; u = pre[v = u]) {
		Splay(u);
		rt[R(u)] = true, rt[R(u) = v] = false;
		up(u);
	}
	return v;
}

//判断是否是同树(真实的树,非splay)
bool judge(int u, int v) {
	while (pre[u])
		u = pre[u];
	while (pre[v])
		v = pre[v];
	return u == v;
}

//使u成为它所在的树的根
void mroot(int u) {
	Access(u);
	Splay(u);
	Update_Rev(u);
}

//调用后u是原来u和v的lca,v和ch[u][1]分别存着lca的2个儿子(原来u和v所在的2颗子树)
void lca(int &u, int &v) {
	Access(v), v = 0;
	while (u) {
		Splay(u);
		if (!pre[u])
			return;
		rt[R(u)] = true;
		rt[R(u) = v] = false;
		up(u);
		u = pre[v = u];
	}
}

//连接两棵树  u接在v上
void link(int u, int v) {
	if (judge(u, v)) {
		puts("-1");
		return;
	}
	mroot(u);
	pre[u] = v;
}

//使u成为u所在树的根,并且v和它父亲的边断开
void cut(int u, int v) {
	if (u == v || !judge(u, v)) {
		puts("-1");
		return;
	}
	mroot(u);
	Splay(v);
	pre[L(v)] = pre[v];
	pre[v] = 0;
	rt[L(v)] = true;
	L(v) = 0;
	up(v);
}

//u-v路径+w
void ADD(int u, int v, int w) {
	if (!judge(u, v)) {
		puts("-1");
		return;
	}
	lca(u, v);
	Update_Add(R(u), w);
	Update_Add(v, w);
	key[u] += w;
	up(u);
}

//u-v路径最大值
void query(int u, int v) {
	if (!judge(u, v)) {
		puts("-1");
		return;
	}
	lca(u, v);
	printf("%d\n", max(max(Max[v], Max[R(u)]), key[u]));
}

void addedge(int u, int v) {
	ed[tot].v = v;
	ed[tot].next = head[u];
	head[u] = tot++;
}

//利用dfs初始化pre数组  建立LCT
void dfs(int u) {
	for (int i = head[u]; ~i; i = ed[i].next) {
		int v = ed[i].v;
		if (pre[v] != 0)
			continue;
		pre[v] = u;
		dfs(v);
	}
}

int main() {
	int n, q, u, v;
	while (scanf("%d", &n) == 1) {
		tot = 0;
		memset(head, -1, sizeof(head));
		memset(pre, 0, sizeof(pre));
		memset(ch, 0, sizeof(ch));
		memset(rev, 0, sizeof(rev));
		memset(add, 0, sizeof(add));
		for (int i = 0; i <= n; i++)
			rt[i] = true;
		Max[0] = -2000000000;
		for (int i = 1; i < n; i++) {
			scanf("%d%d", &u, &v);
			addedge(u, v);
			addedge(v, u);
		}
		for (int i = 1; i <= n; i++) {
			scanf("%d", &key[i]);
			Max[i] = key[i];
		}
		scanf("%d", &q);
		pre[1] = -1;
		dfs(1);
		pre[1] = 0;
		int op;
		while (q--) {
			scanf("%d", &op);
			if (op == 1) {
				int x, y;
				scanf("%d%d", &x, &y);
				link(x, y);
			} else if (op == 2) {
				int x, y;
				scanf("%d%d", &x, &y);
				cut(x, y);
			} else if (op == 3) {
				int w, x, y;
				scanf("%d%d%d", &w, &x, &y);
				ADD(x, y, w);
			} else {
				int x, y;
				scanf("%d%d", &x, &y);
				query(x, y);
			}
		}
		printf("\n");
	}
	return 0;
}
时间: 2024-11-18 18:22:44

HDU 4010 Query on The Trees的相关文章

HDU 4010 Query on The Trees (动态树)(Link-Cut-Tree)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意; 先给你一棵树,有 \(4\) 种操作: 1.如果 \(x\) 和 \(y\) 不在同一棵树上则在\(x-y\)连边. 2.如果 \(x\) 和 \(y\) 在同一棵树上并且 \(x!=y\) 则把 \(x\) 换为树根并把 \(y\) 和 \(y\) 的父亲分离. 3.如果 \(x\) 和 \(y\) 在同一棵树上则 \(x\) 到 \(y\) 的路径上所有的点权值\(+w\). 4

HDU 4010 Query on The Trees(动态树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意:一棵树,四种操作: (1)若x和y不在一棵树上,将x和y连边: (2)若x和y在一棵树上,将x变成树根,将y从x树上分离: (3)若x和y在一棵树上,将x到y路径上的所有值增加det: (4)若x和y在一棵树上,输出x到y路径上的最大值. 思路:1操作用link维护,2操作用cut,34操作先split(x,y),然后对y做tag,并且记录路径的max值. 1 #include<iost

hdu 4010 Query on The Trees(动态树)

题意:给定一幅图的连接情况,给出每个点的权值,四种操作: 1 x y 连接x.y所在子树: 2 x y 将同一棵树上的x,y分离,形成两棵子树: 3 w x y 将x.y之间路径上的所有点权加w: 4 x y 查询x.y路径上点权的最大值: 动态树学习参考:http://www.cnblogs.com/BLADEVIL/p/3510997.html http://wenku.baidu.com/view/75906f160b4e767f5acfcedb http://m.blog.csdn.ne

HDU 4010.Query on The Trees 解题报告

题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点权值+w 4.如果x和y在同一棵树上则输出x到y路径上的最大值 动态树入门题: #include <iostream> #include <cstdio> using namespace std; const int MAXN = 333333; struct node { int v

hdu 4010 Query on the trees LCT

维护一个带点权的无向图森林,支持: 1.删边 2.加边 3.增加某条链所有点的点权 4.求某条链上点权的最大值 大概思路: 前两个需要更改根(即需要翻转标记) 第三个又需要一个标记,第四个每个节点记录该splay中以该节点为根的子树的最大点权. 收获: 1.对于splay前的标记下传可用递归写法, 虽然慢一点,但不容易写错. 2.access的过程中,在边转换完成后要更新节点信息. 3.对于寻找某子树的根,可以一直向上(会途径重边和轻边)找,这样比access+splay快很多,也很好写. 4.

HDOJ 4010 Query on The Trees LCT

LCT: 分割.合并子树,路径上全部点的点权添加一个值,查询路径上点权的最大值 Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2582    Accepted Submission(s): 1208 Problem Description We have met so many problems

HDOJ 题目4010 Query on The Trees(Link Cut Tree连接,删边,路径点权加,路径点权最大值)

Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 3602    Accepted Submission(s): 1587 Problem Description We have met so many problems on the tree, so today we will have a qu

hdu 6191 Query on A Tree(dfs序+可持久化字典树)

题目链接:hdu 6191 Query on A Tree 题意: 给你一棵树,每个节点有一个值,现在有q个询问,每个询问 询问一个u x,问以u为根的子树中,找一个节点,使得这个节点的值与x异或的值最大,输出那个最大的值. 题解: dfs序和一棵可持久化字典树就搞定了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4

HDU 4010 LCT

Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2599    Accepted Submission(s): 1213 Problem Description We have met so many problems on the tree, so today we will have a qu