[BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】

题目链接:BZOJ - 1036

题目分析

这道题可以用树链剖分,块状树等多种方法解决,也可以使用 LCT。

修改某个点的值时,先将它 Splay 到它所在的 Splay 的根,然后修改它的值,再将它 Update 一下。

询问 x, y 两点之间的路径时,假设 x 是深度小的那一个,先 Access(x) ,然后再 Access(y) 的返回值就是 x, y 的 LCA 。

这时从 x 到 LCA 的路径已经在 LCA 处断开了。我们将 x Splay 一下,然后就是 x 所在的 Splay, LCA, Son[LCA][1] 这 3 部分组成了 x, y 的路径。

要特判 x == LCA 的情况。

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

inline void Read(int &Num)
{
	char c = getchar();
	bool Neg = false;
	while (c < ‘0‘ || c > ‘9‘)
	{
		if (c == ‘-‘) Neg = true;
		c = getchar();
	}
	Num = c - ‘0‘; c = getchar();
	while (c >= ‘0‘ && c <= ‘9‘)
	{
		Num = Num * 10 + c - ‘0‘;
		c = getchar();
	}
	if (Neg) Num = -Num;
}

const int MaxN = 30000 + 5, INF = 999999999;

int n, q, Ans;
int A[MaxN], Father[MaxN], Sum[MaxN], Max[MaxN], Son[MaxN][2], Depth[MaxN];

bool isRoot[MaxN];

struct Edge
{
	int v;
	Edge *Next;
} E[MaxN * 2], *P = E, *Point[MaxN];

inline void AddEdge(int x, int y)
{
	++P; P -> v = y;
	P -> Next = Point[x]; Point[x] = P;
}

void DFS(int x, int Fa, int Dep)
{
	Father[x] = Fa; Depth[x] = Dep;
	for (Edge *j = Point[x]; j; j = j -> Next)
	{
		if (j -> v == Fa) continue;
		DFS(j -> v, x, Dep + 1);
	}
}

inline int gmin(int a, int b) {return a < b ? a : b;}
inline int gmax(int a, int b) {return a > b ? a : b;}

inline void Update(int x)
{
	Max[x] = gmax(A[x], gmax(Max[Son[x][0]], Max[Son[x][1]]));
	Sum[x] = A[x] + Sum[Son[x][0]] + Sum[Son[x][1]];
}

void Rotate(int x, int f)
{
	int y = Father[x];
	if (isRoot[y])
	{
		isRoot[y] = false;
		isRoot[x] = true;
	}
	else
	{
		if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;
		else Son[Father[y]][1] = x;
	}
	Father[x] = Father[y];
	Son[y][f ^ 1] = Son[x][f];
	if (Son[x][f]) Father[Son[x][f]] = y;
	Son[x][f] = y;
	Father[y] = x;
	Update(y);
	Update(x);
}

void Splay(int x)
{
	int y;
	while (!isRoot[x])
	{
		y = Father[x];
		if (isRoot[y])
		{
			if (x == Son[y][0]) Rotate(x, 1);
			else Rotate(x, 0);
			break;
		}
		if (y == Son[Father[y]][0])
		{
			if (x == Son[y][0])
			{
				Rotate(y, 1);
				Rotate(x, 1);
			}
			else
			{
				Rotate(x, 0);
				Rotate(x, 1);
			}
		}
		else
		{
			if (x == Son[y][1])
			{
				Rotate(y, 0);
				Rotate(x, 0);
			}
			else
			{
				Rotate(x, 1);
				Rotate(x, 0);
			}
		}
	}
}

int Access(int x)
{
	int y = 0;
	while (x != 0)
	{
		Splay(x);
		isRoot[Son[x][1]] = true;
		Son[x][1] = y;
		if (y) isRoot[y] = false;
		Update(x);
		y = x;
		x = Father[x];
	}
	return y;
}

char Str[10];

int main()
{
	scanf("%d", &n);
	int a, b, LCA;
	for (int i = 1; i <= n - 1; ++i)
	{
		Read(a); Read(b);
		AddEdge(a, b); AddEdge(b, a);
	}
	DFS(1, 0, 0);
	for (int i = 1; i <= n; ++i)
	{
		Read(A[i]);
		isRoot[i] = true;
		Sum[i] = Max[i]= A[i];
	}
	Sum[0] = 0; Max[0] = -INF;
	scanf("%d", &q);
	for (int i = 1; i <= q; ++i)
	{
		scanf("%s", Str);
		Read(a); Read(b);
		if (strcmp(Str, "CHANGE") == 0)
		{
			Splay(a);
			A[a] = b;
			Update(a);
		}
		else if (strcmp(Str, "QMAX") == 0)
		{
			if (Depth[a] > Depth[b]) swap(a, b);
			Access(a);
			LCA = Access(b);
			Splay(a);
			if (a == LCA) Ans = gmax(A[LCA], Max[Son[LCA][1]]);
			else Ans = gmax(A[LCA], gmax(Max[a], Max[Son[LCA][1]]));
			printf("%d\n", Ans);
		}
		else if (strcmp(Str, "QSUM") == 0)
		{
			if (Depth[a] > Depth[b]) swap(a, b);
			Access(a);
			LCA = Access(b);
			Splay(a);
			if (a == LCA) Ans = A[LCA] + Sum[Son[LCA][1]];
			else Ans = A[LCA] + Sum[a] + Sum[Son[LCA][1]];
			printf("%d\n", Ans);
		}
	}
	return 0;
}

  

时间: 2024-10-12 03:20:50

[BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】的相关文章

BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

BZOJ 1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit][Status][Discuss] Description 一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 18615  Solved: 7598[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

树链剖分教程 &amp; bzoj 1036 [ZJOI2008] 树的统计 Count 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24669751 [原题] 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4465  Solved: 1858 [Submit][Status] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

[ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II.

BZOJ 1036 [ZJOI2008]树的统计Count(动态树)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:一棵树,每个节点有一个权值.三种操作:(1)修改某个节点的权值:(2)输出某两个节点之间的权值之和:(3)输出某两个节点之间权值的最大值. 思路:(1)首先说明,在splay中记录一个father,表示当前节点的父节点.但是在这里,在一个树链中,father与在splay中的father的意义是一样的,也就是设v的father是u,那么u的左孩子或者右孩子必然有一个是v.但是

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa