【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题。 代码如下,使用常用的轻重链剖分。

/**************************************************************
	Problem: 1036
	User: Evensgn
	Language: C++
	Result: Accepted
	Time:2468 ms
	Memory:5772 kb
****************************************************************/

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

using namespace std;

const int MaxE = 30000 + 5, MaxN = 30000 + 5;

int n, q, topH, W[MaxN], f[MaxN], dep[MaxN], top[MaxN], son[MaxN], h[MaxN], size[MaxN], A[MaxN];

int Ans;

struct treeNode
{
	int sum, max;
} T[MaxN * 4];

struct edge
{
	int u, v;
	edge *next;
} E[MaxE * 2], *P = E, *point[MaxN];

inline void addedge(int x, int y)
{
	++P; P -> u = x; P -> v = y; P -> next = point[x]; point[x] = P;
}

int DFS_1(int now, int depth, int fa)
{
	f[now] = fa;
	dep[now] = depth;
	int sonSize, maxSonSize = 0;
	size[now] = 1;
	for (edge *j = point[now]; j; j = j -> next)
	{
		if (j -> v != f[now])
		{
			sonSize = DFS_1(j -> v, depth + 1, now);
			size[now] += sonSize;
			if (maxSonSize < sonSize)
			{
				son[now] = j -> v;
				maxSonSize = sonSize;
			}
		}
	}
	return size[now];
}

void DFS_2(int now)
{
	if (now != son[f[now]]) top[now] = now;
	else top[now] = top[f[now]];
	h[now] = ++topH;
	A[h[now]] = W[now];
	if (son[now]) DFS_2(son[now]);
	for (edge *j = point[now]; j; j = j -> next)
		if (j -> v != son[now] && j -> v != f[now]) DFS_2(j -> v);
}

int max(int a, int b)
{
	if (a > b) return a;
	return b;
}

void update(int x)
{
	T[x].sum = T[x * 2].sum + T[x * 2 + 1].sum;
	T[x].max = max(T[x * 2].max, T[x * 2 + 1].max);
}

void buildTree(int x, int s, int t)
{
	if (s == t)
	{
		T[x].sum = A[s];
		T[x].max = A[s];
		return;
	}
	int m = (s + t) >> 1;
	buildTree(x * 2, s, m);
	buildTree(x * 2 + 1, m + 1, t);
	update(x);
}

void change(int x, int s, int t, int loc, int num)
{
	if (s == t)
	{
		T[x].sum = num;
		T[x].max = num;
		return;
	}
	int m = (s + t) >> 1;
	if (loc <= m) change(x * 2, s, m, loc, num);
	else change(x * 2 + 1, m + 1, t, loc, num);
	update(x);
}

int getMax(int x, int s, int t, int l, int r)
{
	if (l <= s && r >= t)
		return T[x].max;
	int m = (s + t) >> 1, ans = -999999999;
	if (l <= m) ans = max(ans, getMax(x * 2, s, m, l, r));
	if (r >= m + 1) ans = max(ans, getMax(x * 2 + 1, m + 1, t, l, r));
	return ans;
}

int getSum(int x, int s, int t, int l, int r)
{
	if (l <= s && r >= t)
		return T[x].sum;
	int m = (s + t) >> 1, ans = 0;
	if (l <= m) ans += getSum(x * 2, s, m, l, r);
	if (r >= m + 1) ans += getSum(x * 2 + 1, m + 1, t, l, r);
	return ans;
}

void queryMax(int s, int t)
{
	int f1, f2;
	f1 = 0; f2 = 1;
	while (f1 != f2)
	{
		f1 = top[s];
		f2 = top[t];
		if (f1 != f2)
		{
			if (dep[f1] >= dep[f2])
			{
				Ans = max(Ans, getMax(1, 1, n, h[f1], h[s]));
				s = f[f1];
			}
			else
			{
				Ans = max(Ans, getMax(1, 1, n, h[f2], h[t]));
				t = f[f2];
			}
		}
		else
		{
			if (s == t) Ans = max(Ans, getMax(1, 1, n, h[s], h[s]));
			else
			{
				if (dep[s] >= dep[t]) Ans = max(Ans, getMax(1, 1, n, h[t], h[s]));
				else Ans = max(Ans, getMax(1, 1, n, h[s], h[t]));
			}
		}
	}
}

void querySum(int s, int t)
{
	int f1, f2;
	f1 = 0; f2 = 1;
	while (f1 != f2)
	{
		f1 = top[s];
		f2 = top[t];
		if (f1 != f2)
		{
			if (dep[f1] >= dep[f2])
			{
				Ans += getSum(1, 1, n, h[f1], h[s]);
				s = f[f1];
			}
			else
			{
				Ans += getSum(1, 1, n, h[f2], h[t]);
				t = f[f2];
			}
		}
		else
		{
			if (s == t) Ans += getSum(1, 1, n, h[s], h[s]);
			else
			{
				if (dep[s] >= dep[t]) Ans += getSum(1, 1, n, h[t], h[s]);
				else Ans += getSum(1, 1, n, h[s], h[t]);
			}
		}
	}
}

int main()
{
//	freopen("1.in", "r", stdin);
	scanf("%d", &n);
	int a, b;
	char flag[10];
	for (int i = 1; i <= n - 1; i++)
	{
		scanf("%d%d", &a, &b);
		addedge(a, b);
		addedge(b, a);
	}
	for (int i = 1; i <= n; i++) scanf("%d", &W[i]);
	DFS_1(1, 1, 0);
	topH = 0; top[1] = 1; DFS_2(1);
	buildTree(1, 1, n);
	scanf("%d", &q);
	for (int i = 1; i <= q; i++)
	{
		scanf("%s%d%d", flag, &a, &b);
		if (!strcmp(flag, "QMAX"))
		{
			Ans = -999999999;
			queryMax(a, b);
			printf("%d\n", Ans);
		}
		else if (!strcmp(flag, "QSUM"))
		{
			Ans = 0;
			querySum(a, b);
			printf("%d\n", Ans);
		}
		else         //Change one node
		{
			change(1, 1, n, h[a], b);
		}
	}
	return 0;
}

【BZOJ 1036】【ZJOI 2008】树的统计,布布扣,bubuko.com

时间: 2024-10-05 16:48:49

【BZOJ 1036】【ZJOI 2008】树的统计的相关文章

zjoi 2008 树的统计——树链剖分

比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护--比如求路径和的话--随着他们各自的链向上走,直至他们在同一条链上为止.比较像lca的方法,只不过这里是按链为单位,而且隔壁的SymenYang说可以用树链剖分做lca..吓哭 然后说说惨痛的调题经历:边表一定要开够啊! 不是n-1 而是2*(n-1)啊! 然后写变量时原始值和映射值要搞清楚啊! 不要搞错了! 还有就是下次求最小值一定看清下界是

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

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

ZJOI 2008 树的统计

ZJOI2008 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入输出格式 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数

BZOJ 1040 ZJOI 2008 骑士 基环树林+树形DP

题目大意:有一些骑士,他们每个人都有一个权值.但是由于一些问题,每一个骑士都特别讨厌另一个骑士.所以不能把他们安排在一起.求这些骑士所组成的编队的最大权值和是多少. 思路:首先貌似是有向图的样子,但是一个人讨厌另一个人,他们两个就不能在一起,所以边可以看成是无向的. n个点,n条无向边,好像是一颗基环树.但其实这是一个基环树林,因为题中并没有说保证图一定联通. 然后就可以深搜了,处理出每一个联通块.其实每一个联通块就是一个基环树,在这个基环树上进行树形DP.求出最大值,然后累加到答案上.答案要开

[BZOJ 1034] [ZJOI 2008] 泡泡堂BNB

1034: [ZJOI2008]泡泡堂BNB Time Limit: 10 SecMemory Limit: 162 MB Description 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏泡泡堂.每一场比赛前,对阵双方的教练向组委会提交一份参赛选手的名单,决定了选手上场的顺序,一经确定,不得修改.比赛中,双方的一号选手,二号选手……,n号选手捉对厮杀,共进行n场比赛.每胜一场比赛得2分,

BZOJ 1038 ZJOI 2008 瞭望塔 半平面交

题目大意:给出一个村庄的轮廓,在这个村庄里可以在随意的地方建一个瞭望塔.这个塔须要足够高,使得可以看得村庄的全貌. 求这个瞭望塔的最小高度. 思路:对于村庄中的每一条边,瞭望塔为了看见它.必需要在这个直线左側的半平面区域.这种话为了满足全部的边的需求,做一次半平面交,瞭望塔的最高点必须在全部边的半平面交的区域内. 例如以下图例子. 全部边的半平面交区域就是上面的图形.设上面半平面的函数关系是F(x).村长的函数关系是G(x),那么问题就转化成了求一个x,使得(F(x) - G(x))最小. 这个

【BZOJ 1036】树的统计Count(树链剖分)

[BZOJ 1036]树的统计Count(树链剖分) 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 12991  Solved: 5233 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: 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