树链剖分刷水

原创 2015年11月21日 11:50:19

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;
}


版权声明:转载请注明 http://blog.csdn.net/huanghongxun/

相关文章推荐

树链剖分

  • 2015年09月22日 16:44
  • 800KB
  • 下载

【算法与数据结构】 树链剖分

  • 2016年07月29日 19:49
  • 919KB
  • 下载

POJ 3237 Tree (树链剖分 路径更新)

比裸的树链剖分多个区间更新 /* *********************************************** Author :kuangbin Created Ti...
  • Ezereal
  • Ezereal
  • 2016年09月19日 15:21
  • 148

树链剖分模板

  • 2015年03月05日 08:33
  • 5KB
  • 下载

树链剖分模板题

  • 2015年05月19日 09:38
  • 3KB
  • 下载

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

LCA(Lowest Common Ancestor 最近公共祖先)定义如下:在一棵树中两个节点的LCA为这两个节点所有的公共祖先中深度最大的节点。 如图,节点11与节点6的LCA为节点4,节点...

[BZOJ1036][ZJOI2008]树的统计Count(树链剖分)

不成功,便成仁!

树上方法总结 LCA 树上倍增 树链剖分 树的直径 重心

树是一种非常有条理的数据结构,从很多方面来看都是这样。每一个节点有其唯一确定的父亲节点,也有唯一确定的边权或点权。因为没有环,树上可以方便地dfs。并且很多链上的做法都可以推广到树上。 树上常用或不...
  • myjs999
  • myjs999
  • 2017年11月06日 21:31
  • 205

【bzoj 3083】遥远的国度(树链剖分+线段树)

拈月入弦,琴语碎

BZOJ[2157]旅游 树链剖分+线段树

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2157 DescriptionRay 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市...
  • WADuan2
  • WADuan2
  • 2017年10月18日 20:51
  • 58
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:树链剖分刷水
举报原因:
原因补充:

(最多只允许输入30个字)