关闭

树链剖分刷水

标签: bzoj
313人阅读 评论(0) 收藏 举报
分类:

BZOJ 2836 魔法树

链改+子树查,和NOI 2015那道差不多吧。。

#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;i++)
typedef long long ll;
using std::swap;
ll read() {
	ll s = 0; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar());
	for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
	return s;
}
const int N = 200001, M = N * 2;
int n, id = 0, cnt = 0;
int dep[N], son[N], sz[N], fa[N], top[N], pos[N], end[N];
int head[N], next[M], to[M];
ll sum[M], lazy[M];

void add(int u, int v) {
	next[++cnt] = head[u]; head[u] = cnt; to[cnt] = v;
	next[++cnt] = head[v]; head[v] = cnt; to[cnt] = u;
}

void dfs1(int x) {
	son[x] = 0; sz[x] = 1;
	for (int i = head[x]; i; i = next[i])
		if (to[i] != fa[x]) {
			fa[to[i]] = x; dep[to[i]] = dep[x] + 1;
			dfs1(to[i]); sz[x] += sz[to[i]];
			if (sz[son[x]] < sz[to[i]]) son[x] = to[i];
		}
}

void dfs2(int x, int t) {
	top[x] = t; pos[x] = ++id;
	if (son[x]) dfs2(son[x], t);
	for (int i = head[x]; i; i = next[i])
		if (to[i] != son[x] && to[i] != fa[x])
			dfs2(to[i], to[i]);
	end[x] = id;
}

void update(int t, int l, int r, ll v) {
    sum[t] += (r - l + 1) * v; lazy[t] += v;
}

void pushdown(int t, int l, int r) {
	int mid = l + r >> 1; 
	update(t * 2, l, mid, lazy[t]);
	update(t * 2 + 1, mid + 1, r, lazy[t]);
	lazy[t] = 0;
}

void modify(int t, int l, int r, int ql, int qr, ll plus) {
	if (l == ql && r == qr) { update(t, l, r, plus); return; }
	pushdown(t, l, r);
	int mid = l + r >> 1;
	if (qr <= mid) modify(t * 2, l, mid, ql, qr, plus);
	else if (ql > mid) modify(t * 2 + 1, mid + 1, r, ql, qr, plus);
	else modify(t * 2, l, mid, ql, mid, plus),
		modify(t * 2 + 1, mid + 1, r, mid + 1, qr, plus);
	sum[t] = sum[t * 2] + sum[t * 2 + 1];
}

ll query(int t, int l, int r, int ql, int qr) {
	if (l == ql && r == qr) return sum[t];
	pushdown(t, l, r);
	int mid = l + r >> 1;
	if (qr <= mid) return query(t * 2, l, mid, ql, qr);
	else if (ql > mid) return query(t * 2 + 1, mid + 1, r, ql, qr);
	else return query(t * 2, l, mid, ql, mid) +
		query(t * 2 + 1, mid + 1, r, mid + 1, qr);
}

void treeModify(int x, int y, ll c) {
	int fx = top[x], fy = top[y];
	while (fx != fy) {
		if (dep[fx] < dep[fy]) swap(fx, fy), swap(x, y);
		modify(1, 1, n, pos[fx], pos[x], c);
		x = fa[fx], fx = top[x];
	}
	if (dep[x] > dep[y]) swap(x, y);
	modify(1, 1, n, pos[x], pos[y], c);
}

int main() {
	int i, x, y, q; ll z; char ch[8];
	n = read();
	FOR(i,2,n) add(read()+1, read()+1);
	q = read();
	dfs1(1); dfs2(1, 1);
	while (q--) {
		scanf("%s", ch);
		if (ch[0] == 'A') { // Add
			x = read()+1, y = read()+1, z = read();
			treeModify(x, y, z);
		} else { // Query
			x = read()+1;
			printf("%lld\n", query(1, 1, n, pos[x], end[x]));
		}
	}
	return 0;
}

2836: 魔法树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 152  Solved: 61
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

4
0 1
1 2
2 3
4
Add 1 3 1
Query 0
Query 1
Query 2

Sample Output

3
3
2



T2 HAOI 2015, BZOJ 4034

稍微改下就好了。。竟然忘吧快速读入读负数给写回来WA了几次。。真是作死。。

#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;i++)
typedef long long ll;
using std::swap;
ll read() {
	ll s = 0, f = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
	for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
	return s * f;
}
const int N = 200001, M = N * 2;
int n, id = 0, cnt = 0;
int dep[N], son[N], sz[N], fa[N], top[N], pos[N], end[N];
int head[N], next[M], to[M];
ll sum[M], lazy[M];

void add(int u, int v) {
	next[++cnt] = head[u]; head[u] = cnt; to[cnt] = v;
	next[++cnt] = head[v]; head[v] = cnt; to[cnt] = u;
}

void dfs1(int x) {
	son[x] = 0; sz[x] = 1;
	for (int i = head[x]; i; i = next[i])
		if (to[i] != fa[x]) {
			fa[to[i]] = x; dep[to[i]] = dep[x] + 1;
			dfs1(to[i]); sz[x] += sz[to[i]];
			if (sz[son[x]] < sz[to[i]]) son[x] = to[i];
		}
}

void dfs2(int x, int t) {
	top[x] = t; pos[x] = ++id;
	if (son[x]) dfs2(son[x], t);
	for (int i = head[x]; i; i = next[i])
		if (to[i] != son[x] && to[i] != fa[x])
			dfs2(to[i], to[i]);
	end[x] = id;
}

void update(int t, int l, int r, ll v) {
    sum[t] += (r - l + 1) * v; lazy[t] += v;
}

void pushdown(int t, int l, int r) {
	int mid = l + r >> 1; 
	update(t * 2, l, mid, lazy[t]);
	update(t * 2 + 1, mid + 1, r, lazy[t]);
	lazy[t] = 0;
}

void modify(int t, int l, int r, int ql, int qr, ll plus) {
	if (l == ql && r == qr) { update(t, l, r, plus); return; }
	pushdown(t, l, r);
	int mid = l + r >> 1;
	if (qr <= mid) modify(t * 2, l, mid, ql, qr, plus);
	else if (ql > mid) modify(t * 2 + 1, mid + 1, r, ql, qr, plus);
	else modify(t * 2, l, mid, ql, mid, plus),
		modify(t * 2 + 1, mid + 1, r, mid + 1, qr, plus);
	sum[t] = sum[t * 2] + sum[t * 2 + 1];
}

ll query(int t, int l, int r, int ql, int qr) {
	if (l == ql && r == qr) return sum[t];
	pushdown(t, l, r);
	int mid = l + r >> 1;
	if (qr <= mid) return query(t * 2, l, mid, ql, qr);
	else if (ql > mid) return query(t * 2 + 1, mid + 1, r, ql, qr);
	else return query(t * 2, l, mid, ql, mid) +
		query(t * 2 + 1, mid + 1, r, mid + 1, qr);
}

ll treeQuery(int x, int y) {
	int fx = top[x], fy = top[y]; ll ans = 0;
	while (fx != fy) {
		if (dep[fx] < dep[fy]) swap(fx, fy), swap(x, y);
		ans += query(1, 1, n, pos[fx], pos[x]);
		x = fa[fx], fx = top[x];
	}
	if (dep[x] > dep[y]) swap(x, y);
	return ans + query(1, 1, n, pos[x], pos[y]);
}

int main() {
	static ll w[N];
	int i, x, y, q, t;
	n = read(), q = read();
	FOR(i,1,n) w[i] = read();
	FOR(i,2,n) add(read(), read());
	dfs1(1); dfs2(1, 1);
	FOR(i,1,n) modify(1,1,n,pos[i],pos[i],w[i]);
	while (q--) {
		t = read(); x = read();
		switch(t) {
		case 1:
			modify(1, 1, n, pos[x], pos[x], read());
			break;
		case 2:
			modify(1, 1, n, pos[x], end[x], read());
			break;
		case 3:
			printf("%lld\n", treeQuery(1, x));
			break;
		}
	}
	return 0;
}


4034: [HAOI2015]T2

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1030  Solved: 356
[Submit][Status][Discuss]

Description

 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

 第一行包含两个整数 N, M 。表示点数和操作数。

接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output

 对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input

5 5

1 2 3 4 5

1 2

1 4

2 3

2 5

3 3

1 2 1

3 5

2 1 2

3 3

Sample Output

6

9

13

HINT

 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不


会超过 10^6 。


Query on a tree SPOJ 375



You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1.

We will ask you to perfrom some instructions of the following form:

  • CHANGE i ti : change the cost of the i-th edge to ti
    or
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
  • The next lines contain instructions "CHANGE i ti" or "QUERY a b",
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "QUERY" operation, write one integer representing its result.

Example

Input:
1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Output:
1
3
#include <cstdio>
#include <algorithm>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;i++)
using std::swap; using std::max;
int read() {
	int s = 0, f = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
	for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
	return s * f;
}
const int N = 200001, M = N * 2;
int n, id = 0, cnt = 0;
int dep[N], son[N], sz[N], fa[N], top[N], pos[N], end[N];
int head[N], next[M], to[M], ma[M];

void add(int u, int v) {
	next[++cnt] = head[u]; head[u] = cnt; to[cnt] = v;
	next[++cnt] = head[v]; head[v] = cnt; to[cnt] = u;
}

void dfs1(int x) {
	son[x] = 0; sz[x] = 1;
	for (int i = head[x]; i; i = next[i])
		if (to[i] != fa[x]) {
			fa[to[i]] = x; dep[to[i]] = dep[x] + 1;
			dfs1(to[i]); sz[x] += sz[to[i]];
			if (sz[son[x]] < sz[to[i]]) son[x] = to[i];
		}
}

void dfs2(int x, int t) {
	top[x] = t; pos[x] = ++id;
	if (son[x]) dfs2(son[x], t);
	for (int i = head[x]; i; i = next[i])
		if (to[i] != son[x] && to[i] != fa[x])
			dfs2(to[i], to[i]);
	end[x] = id;
}

void modify(int t, int l, int r, int x, int v) {
	if (l == r) { ma[t] = v; return; }
	int mid = l + r >> 1;
	if (x <= mid) modify(t * 2, l, mid, x, v);
	else if (x > mid) modify(t * 2 + 1, mid + 1, r, x, v);
	ma[t] = max(ma[t * 2], ma[t * 2 + 1]);
}

int query(int t, int l, int r, int ql, int qr) {
	if (l == ql && r == qr) return ma[t];
	int mid = l + r >> 1;
	if (qr <= mid) return query(t * 2, l, mid, ql, qr);
	else if (ql > mid) return query(t * 2 + 1, mid + 1, r, ql, qr);
	else return max(query(t * 2, l, mid, ql, mid),
		query(t * 2 + 1, mid + 1, r, mid + 1, qr));
}

int treeQuery(int x, int y) {
	int fx = top[x], fy = top[y], ans = 0;
	while (fx != fy) {
		if (dep[fx] < dep[fy]) swap(fx, fy), swap(x, y);
		ans = max(ans, query(1, 1, n, pos[fx], pos[x]));
		x = fa[fx], fx = top[x];
	}
	if (dep[x] > dep[y]) swap(x, y);
	return max(ans, query(1, 1, n, pos[x], pos[y]));
}

int main() {
	static int a[M], b[M], c[M];
	char ch[8];
	int i, x, y, z, t;
	t = read();
	while (t--) {
		n = read();
		memset(ma, 0, sizeof ma);
		memset(head, 0, sizeof head);
		FOR(i,2,n) a[i] = read(), b[i] = read(), c[i] = read(), add(a[i], b[i]);
		dfs1(1); dfs2(1, 1);
		FOR(i,2,n) {
			if (dep[a[i]] > dep[b[i]]) swap(a[i], b[i]);
			modify(1, 1, n, pos[b[i]], c[i]);
		}
		while (1) {
			scanf("%s", ch);
			if (ch[0] == 'C')
				x = read(), y = read(), modify(1, 1, n, pos[b[x]], y);
			else if (ch[0] == 'Q')
				x = read(), y = read(), printf("%d\n", treeQuery(x, y));
			else break;
		}
	}
	return 0;
}


0
0
查看评论

GIMP 笔刷的制作

step 1:新建256x256大小的灰度图片.并用6参考线.如下,每个区域内化成不同的形状.   step 2:菜单->滤镜->模糊->高斯模糊10px. step 3:菜单->滤镜->扭曲->I-wap.   step 4:将图片...
  • wide288
  • wide288
  • 2014-11-05 15:14
  • 1261

树链剖分入门讲解

“在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。树链,就是树上的路径。剖分,就是把路径分类为重链和轻链。 记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1),top...
  • bobodem
  • bobodem
  • 2016-08-26 17:22
  • 2009

树链剖分小结及题目

我们经常会遇到这样一类题目:给出一棵树,询问树上u,v两点路径间的最值,合值,更新u,v路径上的点权或边权,或者区间更新etc,此时如果单纯的用线段树或者树状数组去搞,很明显问题不能够得到完美解决,此时就需要更高级的数据结构去对树进行重新构造,也就是通常说的树链剖分。 一.树链剖分 树链剖分,顾名思...
  • Forever_wjs
  • Forever_wjs
  • 2016-08-04 10:28
  • 2141

树链剖分模板题汇总

记录几个树链剖分的模板题,包括点操作,边操作和带方向的操作。点操作HDU 3966#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #includ...
  • r_clover
  • r_clover
  • 2016-03-02 19:22
  • 607

野田圣子、希尔顿、松下幸之助,都喝过马桶水吗?

野田圣子、希尔顿、松下幸之助,都喝过马桶水吗?
  • godofdsp
  • godofdsp
  • 2014-09-28 14:24
  • 4056

树链剖分求LCA(最近公共祖先)

LCA(Lowest Common Ancestor 最近公共祖先)定义如下:在一棵树中两个节点的LCA为这两个节点所有的公共祖先中深度最大的节点。 如图,节点11与节点6的LCA为节点4,节点12与节点1的LCA为8,节点11与节点10的LCA为10。 现在我们来了解一下LCA我认为最好的...
  • wazwaztime
  • wazwaztime
  • 2016-05-15 11:02
  • 2889

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

【原题】 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 4465  Solved: 1858 [Submit][...
  • u013724185
  • u013724185
  • 2014-04-28 22:27
  • 5687

hdu 3966 Aragorn's Story 树链剖分 bfs实现(不知道为什么会RE)

题意:给出一棵树,增加或减少树上一条路径上点的值,询问点的值 思路:学习了树链剖分,并且使用了红书的bfs版本,然后映射到线段树上,手动扩栈后还是一直RE,真的不知道怎么弄了,红书上很多数据结构在这道题没有用上,但也加上了自己的理解 希望各位神犇路过看下,不知道为什么会re 题目链接:h...
  • wyt734933289
  • wyt734933289
  • 2016-08-06 11:48
  • 274

codeforces 733F (树链剖分 RMQ)

题目链接:点击这里题意:给出一个图,每条边有权值和花费c,每次花费c能使的权值-1。给出一个预算,求减完权值后的一个最小生成树。观察到最优的策略必然是只减少一条边的权值。于是首先先将初始权值做一次最小生成树。然后枚举所有的边,如果这条边是生成树的边,求出预算都花在这条边上的结果;如果非树边,就在这条...
  • morejarphone
  • morejarphone
  • 2016-11-03 21:33
  • 415

刷水~~~~~~~~~~~

从放假开始一直到今天,基本上早起一水,饭后一水,再加上蛋疼一水……直到到今天,把一位我觉得很强大的Acmer给的 zoj分类 里的水题全部A掉了,感觉,自己真的老了,都是陈题,但正确率也只有一半而已。还有就是英文看的好痛苦啊,我都是开着有道写的,不知道牛牛们是不是全部靠自己的词汇
  • l04205613
  • l04205613
  • 2011-02-07 15:51
  • 612
    个人资料
    • 访问:176904次
    • 积分:6141
    • 等级:
    • 排名:第4824名
    • 原创:449篇
    • 转载:7篇
    • 译文:0篇
    • 评论:7条
    神犇们的后庭院
    wzq_QwQ http://blog.csdn.net/wzq_QwQ
    vmurder http://blog.csdn.net/vmurder/
    PoPoQQQ http://blog.csdn.net/popoqqq/
    YJQ神犇 http://tarawa.github.io/
    ?神?论文
    http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf