树链剖分刷水

原创 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/ 举报

相关文章推荐

【树链剖分】[BZOJ 4196]软件包管理器

实际上就是个树链剖分,每次询问自己需要的到根节点中有多少开/开了,然后根据需要输出然后线段树Update的时候改一下改成每次更新全部,直接覆盖就行,每次扫描出来的一段肯定是上面半段开下面半段不开(分成...

[hdu 5963 朋友] 博弈SG函数+树链剖分

[hdu 5963 朋友] 博弈SG函数+树链剖分1. 题目链接:[hdu 5963 朋友] 2. 题意描述中文题目,直接copy题面了。Problem DescriptionB君在围观一群男生和一群...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

HYSBZ 1036 树的统计Count 树链剖分

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:Description   一棵树上有n个节点,编号分别为1到...

BZOJ 4390: [Usaco2015 dec]Max Flow|树链剖分

lca+求个差分就ok啦 感觉树链剖分求lca会快一点然后就没用倍增 写完后交上就哇(wa)了一发 然后发现连了单向边 我** 第二遍交A个感觉异常舒畅 然后发现跑了6s坐 稳了倒数rank1 这酸爽...

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

题目地址:BZOJ 1036 树链剖分裸题,需要用线段树同时维护最大值与和值两个信息,只是代码量大一点而已。。 代码如下:#include #include #include #includ...

HDU 3966 Aragorn's Story(树链剖分+线段树区间更新+手动扩大内存)

题意: 给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K ...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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