题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5221
题意:
给定一棵树,每个结点上有一个权值,然后给Q个操作,每个操作为:1. 占领这个树上两个结点路径上的所有结点,包括起点和终点;2. 取消某个结点的占领; 3. 占领以某个结点为根的整棵子树; 对于每个操作,返回完成这个操作后整棵树被占领结点的权值之和
思路:
操作1和2是树链剖分的基础操作不详述,操作3用到了树链剖分的一个特性,以结点k为根的子树,树链剖分完在线段上是一段连续的序列,在树链剖分的第二次dfs过程中用sontree数组顺便记录以j为根的子树,其在线段中对应的最大一个id值,把这个操作转换为线段树上的区间更新操作
在操作线段树时,区间更新需要打懒标记,不然会超时
代码:
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<functional>
#pragma comment(linker, "/STACK:102400000,102400000")//C++
using namespace std;
const double PI = 3.141592653589793238462643383279502884197169399;
const int MAXINT = 0x7fffffff;
const int MAXSIZE = 100000 + 5;
int n,q;
int fa[MAXSIZE], siz[MAXSIZE], son[MAXSIZE], dep[MAXSIZE], top[MAXSIZE], tid[MAXSIZE], sontree[MAXSIZE], ptid[MAXSIZE], w[MAXSIZE];
int first[MAXSIZE], gnext[2*MAXSIZE], to[2*MAXSIZE], edge;
int tsum;
int ans;
void dfs_1(int v,int father,int depth){
siz[v] = 1;
dep[v] = depth;
fa[v] = father;
son[v] = 0;
int i=first[v];
while (i){
int u = to[i];
if (u!=father){
dfs_1(u,v,depth+1);
siz[v]+=siz[u];
if (siz[u]>siz[son[v]]) son[v] = u;
}
i = gnext[i];
}
return;
}
void dfs_2(int v, int tp){
tid[v] = ++tsum;
ptid[tsum] = v;
top[v] = tp;
sontree[v] = tid[v];
if (son[v] != 0){
dfs_2(son[v], top[v]); //使重链在线段上连续
sontree[v] = sontree[son[v]];
}
int i=first[v];
while (i){
int u = to[i];
if (u!=fa[v] && u!=son[v]){
dfs_2(u, u);
if (sontree[v] < sontree[u]) sontree[v] = sontree[u];
}
i = gnext[i];
}
return ;
}
struct node{
int l, r;
int sum, wsum;
bool all;
int mid(){
return (l + r) / 2;
}
};
node tree[(MAXSIZE << 2) + 5];
//初始状态 BuildTree(0,1,n)
void BuildTree(int root, int l, int r){
tree[root].l = l; tree[root].r = r; tree[root].sum=0; tree[root].all = false;
if (l != r){
BuildTree(root * 2 + 1, l, (l + r) / 2);
BuildTree(root * 2 + 2, (l + r) / 2 + 1, r);
tree[root].wsum = tree[(root<<1)+1].wsum + tree[(root<<1)+2].wsum;
}
else{
tree[root].wsum = w[ptid[l]];
}
return;
}
//更新节点 (0,i,w)
void t_insert(int root, int i){
if (tree[root].l == tree[root].r){
tree[root].all = false;
tree[root].sum = 0;
return;
}
else{
if (tree[root].all){
tree[root].all = false;
tree[(root<<1) + 2].all = true;
tree[(root<<1) + 2].sum = tree[(root<<1) + 2].wsum;
tree[(root<<1) + 1].all = true;
tree[(root<<1) + 1].sum = tree[(root<<1) + 1].wsum;
}
if (i <= tree[root].mid())
t_insert(root * 2 + 1, i);
else
t_insert(root * 2 + 2, i);
tree[root].sum = tree[(root<<1)+1].sum + tree[(root<<1)+2].sum;
}
}
//更新线段[st,en] (0,st,en,w)
void t_update(int root, int st, int en){
if (tree[root].all) return;
if (tree[root].l == st && tree[root].r == en){
tree[root].all = true;
tree[root].sum = tree[root].wsum;
return;
}
if (st > tree[root].mid())
t_update(root * 2 + 2, st, en);
else if (en <= tree[root].mid())
t_update(root * 2 + 1, st, en);
else {
t_update(root * 2 + 1, st, tree[root].mid());
t_update(root * 2 + 2, tree[root].mid() + 1, en);
}
tree[root].sum = tree[(root<<1) + 1].sum + tree[(root<<1) + 2].sum;
return;
}
void g_insert(int a, int b){
gnext[++edge] = first[a];
first[a] = edge;
to[edge] = b;
}
void init(){
memset(first,0,sizeof(first));
memset(siz,0,sizeof(siz));
memset(son,0,sizeof(son));
memset(dep,0,sizeof(dep));
memset(fa,0,sizeof(fa));
memset(top,0,sizeof(top));
memset(tid,0,sizeof(tid));
memset(sontree,0,sizeof(sontree));
memset(ptid,0,sizeof(ptid));
memset(w,0,sizeof(w));
tsum = 0;
edge=0;
}
int main(){
int total;
cin>>total;
while (total--){
init();
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",w+i);
for (int i=1;i<n;++i){
int a,b,c;
scanf("%d %d",&a,&b);
g_insert(a,b);
g_insert(b,a);
}
dfs_1(1,0,0);
dfs_2(1,1);
// for (int i=1;i<=n;++i){
// cout<<"sontree: "<<i<<" "<<tid[i]<<" "<<ptid[sontree[i]]<<" "<<sontree[i]<<endl;
// }
BuildTree(0,1,tsum);
scanf("%d",&q);
for (int i=1;i<=q;++i){
int a;
int u,v;
scanf("%d",&a);
if (a==1){
scanf("%d %d",&u,&v);
int f1 = top[u],f2 = top[v];
while (f1 != f2){
if (dep[f1] < dep[f2]){
swap(f1,f2);
swap(u,v);
}
t_update(0, tid[f1], tid[u]);
u=fa[f1];
f1=top[u];
}
if (u!=v){
if (dep[u] > dep[v]) swap(u,v);
t_update(0, tid[u], tid[v]);
}
else{
t_update(0, tid[u], tid[v]);
}
}
else if (a==2){
scanf("%d",&u);
t_insert(0,tid[u]);
}
else {
scanf("%d",&u);
t_update(0,tid[u],sontree[u]);
}
ans=tree[0].sum;
printf("%d\n",ans);
}
}
return 0;
}