kyeremal-bzoj1036[ZJOI2008]-树的统计count-树链剖分

bzoj1036[ZJOI2008]-树的统计count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit:
162 MB

Submit: 7567  Solved: 3109

[Submit][Status][Discuss]

Description

一棵树上有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本身

Input

输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4

1 2

2 3

4 1

4 2 1 3

12

QMAX 3 4

QMAX 3 3

QMAX 3 2

QMAX 2 3

QSUM 3 4

QSUM 2 1

CHANGE 1 5

QMAX 3 4

CHANGE 3 6

QMAX 3 4

QMAX 2 4

QSUM 3 4

Sample Output

4

1

2

2

10

6

5

6

5

16

HINT

Source

树链剖分:

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

using namespace std;

#define rep(i, l, r) for (int i = l; i <= r; i++)
#define REP(i, l, r) for (int i = l; i >= r; i--)
#define INF 2147483647
#define MAXN 1000010

int n, N = -1, M = 0, m, first[MAXN], next[MAXN], NUM[MAXN], root, T_T, c[MAXN];
int dep[MAXN], siz[MAXN], son[MAXN], fa[MAXN], top[MAXN], w[MAXN];
struct tlist {int x, y;} a[MAXN];
bool vis[MAXN];
struct Tree {int l, r, lc, rc, sum, max;} tree[MAXN];

inline void swap(int &a, int &b) {int t = a; a = b; b = t;}
inline void add(int x, int y) {a[++N].x = x, a[N].y = y, next[N] = first[x], first[x] = N;}

inline void dfs(int x, int d) {
    dep[x] = d;
    siz[x] = 1;
    vis[x] = 1;
    int maxsize = 0, k = 0;
    for (int i = first[x]; ~i; i = next[i])
	if (!vis[a[i].y]) {
	    vis[a[i].y] = 1;
	    dfs(a[i].y, d+1);
	    siz[x] += siz[a[i].y];
	    if (siz[a[i].y] > maxsize) maxsize = siz[a[i].y], k = a[i].y;
	}
    son[x] = k;
}

inline void DFS(int x, int T) {
    top[x] = T;
    vis[x] = 1;
    if (son[x]) w[son[x]] = ++M, NUM[M] = son[x], DFS(son[x], T);
    for (int i = first[x]; ~i; i = next[i])
	if (!vis[a[i].y]) {
	    w[a[i].y] = ++M;
	    NUM[M] = a[i].y;
	    DFS(a[i].y, a[i].y);
	}
}

inline void build_tree(int i, int L, int R) {
    tree[i].l = L, tree[i].r = R;
    if (L == R) {tree[i].sum = tree[i].max = c[NUM[L]]; return;}
    build_tree(tree[i].lc = ++m, L, (L+R) >> 1);
    build_tree(tree[i].rc = ++m, ((L+R) >> 1) + 1, R);
    tree[i].max = max(tree[tree[i].lc].max, tree[tree[i].rc].max);
    tree[i].sum = tree[tree[i].lc].sum + tree[tree[i].rc].sum;
}

inline void modify(int i, int x, int cx) {
    int L = tree[i].l, R = tree[i].r;
    if (x < L || x > R) return;
    if (L == R) {tree[i].sum = tree[i].max = cx; return;}
    modify(tree[i].lc, x, cx);
    modify(tree[i].rc, x, cx);
    tree[i].max = max(tree[tree[i].lc].max, tree[tree[i].rc].max);
    tree[i].sum = tree[tree[i].lc].sum + tree[tree[i].rc].sum;
}

inline int query_max(int i, int ql, int qr) {
    int L = tree[i].l, R = tree[i].r;
    if (qr < L || ql > R) return -INF;
    if (L >= ql && R <= qr) return tree[i].max;
    return max(query_max(tree[i].lc, ql, qr), query_max(tree[i].rc, ql, qr));
}

inline int query_sum(int i, int ql, int qr) {
    int L = tree[i].l, R = tree[i].r;
    if (qr < L || ql > R) return 0;
    if (L >= ql && R <= qr) return tree[i].sum;
    return query_sum(tree[i].lc, ql, qr) + query_sum(tree[i].rc, ql, qr);
}

int main() {
    cin >> n;
    memset(first, -1, sizeof(first));
    memset(next, -1, sizeof(next));
    memset(fa, 0, sizeof(fa));
    rep(i, 1, n-1) {
	int tx, ty;
	scanf("%d%d", &tx, &ty);
	fa[ty] = tx;
	if (!fa[tx]) root = tx;
	add(tx, ty), add(ty, tx);
    }
    rep(i, 1, n) scanf("%d", &c[i]);
    memset(vis, 0, sizeof(vis));
    dfs(root, 1);
    memset(vis, 0, sizeof(vis));
    w[root] = ++M, NUM[M] = root;
    DFS(root, root);
    build_tree(m = 1, 1, n);
    cin >> T_T;
    while (T_T--) {
	char ch[MAXN];
	int tx, ty;
	scanf("%s", ch);
	scanf("%d%d", &tx, &ty);
	if (ch[0] == 'C') modify(1, w[tx], ty);
	if (ch[1] == 'M') {
	    int f1, f2, maxans = -INF;
	    while ((f1 = top[tx]) != (f2 = top[ty])) {
		if (dep[f1] < dep[f2]) swap(f1, f2), swap(tx, ty);
		maxans = max(maxans, query_max(1, w[f1], w[tx]));
		tx = fa[f1];
	    }
	    if (dep[tx] < dep[ty]) swap(tx, ty);
	    maxans = max(maxans, query_max(1, w[ty], w[tx]));
	    cout << maxans << endl;
	}
	if (ch[1] == 'S') {
	    int f1, f2, sumans = 0;
	    while ((f1 = top[tx]) != (f2 = top[ty])) {
		if (dep[f1] < dep[f2]) swap(f1, f2), swap(tx, ty);
		sumans += query_sum(1, w[f1], w[tx]);
		tx = fa[f1];
	    }
	    if (dep[tx] < dep[ty]) swap(tx, ty);
	    sumans += query_sum(1, w[ty], w[tx]);
	    cout << sumans << endl;
	}
    }
    return 0;
}
时间: 2024-10-10 08:16:13

kyeremal-bzoj1036[ZJOI2008]-树的统计count-树链剖分的相关文章

HYSBZ - 1036 树的统计Count 树链剖分 求和+最大值

好水0.0 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #de

【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有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本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n

BZOJ1036: [ZJOI2008]树的统计Count - 树链剖分 -

1036: [ZJOI2008]树的统计Count Description 一棵树上有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本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1

bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

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

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 (树链剖分)(线段树单点修改)

[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 树链剖分模板

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

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

Problem 树的统计 题目大意 一棵树上有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本身 So Lazy No Solution 裸的树链剖分,题解一搜一大把.就连这个都炸了几次.我太菜了... AC

【BZOJ1036】【ZJOI2008】树的统计Count 树链剖分裸题

题解:裸的,没什么好说的. 树链剖分不会的先理解一下重链轻链,然后直接扒我代码理解就行了. 贴代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 30100 #define inf 0x3f3f3f3f using namespace std; struct KSD { int u,v,next; }e[N<<1];