1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 9851   Solved: 3980
[ 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



苟蒻终于知道什么是树链剖分了好开心。。。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;

const int maxn = 3E4 + 30;

int n,m,cur = 0,i,j,cnt = 0,qx,qy,qz,am,as,Now,ret;
int L[maxn],anc[maxn][20],c_sum[maxn*20],c_max[maxn*20],va[maxn],belong[maxn],head[maxn],Size[maxn],next[maxn];
int father[maxn],c_size[maxn],Lt[maxn*20],Rt[maxn*20];
bool vis[maxn],heavy[maxn];

vector <int> v[maxn];
vector <int> c[maxn];

void dfs(int k) 
{
	int Max = 0,t = 0;;
	for (int l = 0; l < v[k].size(); l++) {
		int to = v[k][l];
		if (vis[to]) continue;
		vis[to] = 1;
		father[to] = k;
		L[to] = L[k] + 1;
		dfs(to);
		Size[k] += Size[to];
		if (Size[to] > Max) Max = Size[to],t = to;
	}
	if (t) heavy[t] = 1,next[k] = t;
}

void build_tree(int o,int l,int r)
{
	if (l == r) {
		c_max[o] = c_sum[o] = va[c[cnt][l]];
		return;
	}
	int mid = (l + r) >> 1;
	++cur; Lt[o] = cur;
	build_tree(cur,l,mid);
	++cur; Rt[o] = cur;
	build_tree(cur,mid + 1,r);
	c_max[o] = max(c_max[Lt[o]],c_max[Rt[o]]);
	c_sum[o] = c_sum[Lt[o]] + c_sum[Rt[o]];
}

void search(int k)
{
	++cnt; c_size[cnt] = 0;
	c[cnt].push_back(0);
	while (k) {
		belong[k] = cnt;
		c[cnt].push_back(k);
		k = next[k];
		++c_size[cnt];
	}
	head[cnt] = ++cur;
	build_tree(cur,1,c_size[cnt]);
}

int get_order()
{
	char c_m[10];
	scanf("%s",&c_m);
	if (c_m[0] == 'C') return 1;
	if (c_m[1] == 'M') return 2;
	return 3;
}

void Modify(int o,int l,int r)
{
	if (l == r) {
		c_sum[o] = c_max[o] = qy;
		va[c[qz][l]] = qy;
		return;
	}
	int mid = (l + r) >> 1;
	int Mid = c[qz][mid];
	if (L[Mid] >= L[qx]) Modify(Lt[o],l,mid);
	else Modify(Rt[o],mid + 1,r);
	c_sum[o] = c_sum[Lt[o]] + c_sum[Rt[o]];
	c_max[o] = max(c_max[Lt[o]],c_max[Rt[o]]);
}

int fa(int u,int v)
{
	int log;
	for (log = 0; L[u] - (1<<log) > 0; log++); ++log;
	for (j = log; j >= 0; j--)
		if (L[u] - (1<<j) >= L[v]) u = anc[u][j];
	if (u == v) return u;
	for (j = log; j >= 0; j--)
		if (anc[u][j] != anc[v][j]) {
			u = anc[u][j]; v = anc[v][j];
		}
	return anc[u][0];
}

int solve(int o,int l,int r,int pos)
{
	int ret;
	if (L[c[Now][l]] > L[qz] && L[c[Now][r]] <= L[pos]) {
		as += c_sum[o]; am = max(am,c_max[o]);
		return c[Now][l];
	}
	int mid = (l + r) >> 1;
	int Mid = c[Now][mid];
	if (L[Mid] > L[qz]) {
		if (L[pos] > L[Mid])solve(Rt[o],mid + 1,r,pos);
		return solve(Lt[o],l,mid,pos);
	}
	else return solve(Rt[o],mid + 1,r,pos);
}

void Up(int k)
{
	for (;;) {
		if (!heavy[k] || heavy[k] && k == qz) as += va[k]; am = max(am,va[k]);
		if (k == qz) return;
		if (!heavy[k]) {
			k = father[k]; continue;
		}
		Now = belong[k];
		int ret = solve(head[Now],1,c_size[Now],k);
		k = ret;
		k = father[k];
	}
}

void Q()
{
	as = 0; am = -2E9;
	Up(qx); Up(qy);
	as -= va[qz];
}

void dfs2(int k)
{
	anc[k][0] = father[k];
	for (int log = 1; L[k] - (1<<log) > 0; log++) 
		anc[k][log] = anc[anc[k][log-1]][log-1];
	for (int l = 0; l < v[k].size(); l++) {
		int to = v[k][l];
		if (vis[to]) continue;
		vis[to] = 1;
		dfs2(to);
	}
}

int main()
{
	#ifdef YZY
		freopen("yzy.txt","r",stdin);
	#endif
	
	memset(anc,-1,sizeof(anc));
	cin >> n;
	for (i = 1; i < n; i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	
	for (i = 1; i <= n; i++) {
		scanf("%d",&va[i]);
		father[i] = i;
		anc[i][0] = i; Size[i] = 1;
	}
	
	memset(heavy,0,sizeof(heavy));
	memset(vis,0,sizeof(vis));
	L[1] = 1; vis[1] = 1;
	dfs(1);
	
	memset(vis,0,sizeof(vis));
	vis[1] = 1;
	dfs2(1);
	anc[1][0] = -1;
	
	for (i = 1; i <= n; i++)
		if (heavy[i] && !heavy[father[i]]) search(i);
	
	cin >> m;
	while (m--) {
		int opt = get_order();
		
		if (opt == 1) {
			scanf("%d%d",&qx,&qy);
			qz = belong[qx];
			if (qz) Modify(head[qz],1,c_size[qz]);
			else va[qx] = qy;
		}
		
		if (opt == 2) {
			scanf("%d%d",&qx,&qy);
			if (L[qx] < L[qy]) swap(qx,qy);
			if (qx == qy) qz = qx;
			else qz = fa(qx,qy);
			Q(); printf("%d\n",am);
		}
		
		if (opt == 3) {
			scanf("%d%d",&qx,&qy);
			if (L[qx] < L[qy]) swap(qx,qy);
			if (qx == qy) qz = qx;
			else qz = fa(qx,qy);
			Q(); printf("%d\n",as);
		}
	}
	return 0;
}


你可能感兴趣的:(1036: [ZJOI2008]树的统计Count)