http://acm.hdu.edu.cn/showproblem.php?pid=5221
树链剖分,树形转线性,每个节点跳到lca,最多log次,每条重链的节点是连续的,用线段树去维护,总复杂度是O(MlogNlogN),第一种操作是O(logNlogN)的,二三操作是O(logN)的。可以过…(可以说,没有更快的方法了
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define clr(a) memset(a,0,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define MAXN 200100
#define N
#define M 22
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
class Stack{
public:
int st[MAXN],num;
inline void clear(){
num=0;
}
inline void push(int x){
st[num++]=x;
}
inline void pop(){
num--;
}
inline int top(){
return st[num-1];
}
inline int size(){
return num;
}
inline bool empty(){
return !num;
}
}st1,st2;
int n,vto[MAXN],rvto[MAXN];
struct Edge{
int from,to,next,val;
bool heavy;
}edge[MAXN<<1];
int head[MAXN],num_edge;
inline void add_Edge(int from,int to){
int t=++num_edge;
edge[t].from=from;
edge[t].to=to;
edge[t].next=head[from];
edge[t].heavy=false;
head[from]=t;
}
int fa[MAXN],dep[MAXN],siz[MAXN],upto[MAXN],f[MAXN][M],maxto[MAXN];
int dfs_clocks,uptemp,maxidep;
inline void dfs1(){
st1.clear();
st2.clear();
st1.push(1);
fa[1]=-1;
dep[1]=0;
int now,to;
maxidep=0;
while(!st1.empty()){
now=st1.top();
st1.pop();
st2.push(now);
for(int i=head[now];i!=-1;i=edge[i].next){
to=edge[i].to;
if(fa[now]==to) continue;
fa[to]=now;
dep[to]=dep[now]+1;
maxidep=max(maxidep,dep[to]);
st1.push(to);
}
}
while(!st2.empty()){
now=st2.top();
st2.pop();
siz[now]=1;
int e=-1,maxi=-INT;
for(int i=head[now];i!=-1;i=edge[i].next){
to=edge[i].to;
if(fa[now]==to) continue;
siz[now]+=siz[to];
if(siz[to]>maxi){
e=i;
maxi=siz[to];
}
}
if(e!=-1) edge[e].heavy=true;
}
}
inline void dfs2(){
dfs_clocks=0;
st1.clear();
st2.clear();
int now=1,e=-1;
vto[now]=++dfs_clocks;
rvto[dfs_clocks]=now;
upto[1]=uptemp=1;
for(int i=head[now];i!=-1;i=edge[i].next){
if(edge[i].heavy) e=i;
else st1.push(i);
}
if(e!=-1) st1.push(e);
st2.push(now);
while(!st1.empty()){
int nowe=st1.top();
st1.pop();
now=edge[nowe].to;
st2.push(now);
vto[now]=++dfs_clocks;
rvto[dfs_clocks]=now;
if(!edge[nowe].heavy) uptemp=now;
upto[now]=uptemp;
int e=-1,to;
for(int i=head[now];i!=-1;i=edge[i].next){
to=edge[i].to;
if(fa[now]==to) continue;
if(edge[i].heavy) e=i;
else st1.push(i);
}
if(e!=-1) st1.push(e);
}
while(!st2.empty()){
int now=st2.top();
st2.pop();
maxto[now]=vto[now];
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(fa[now]==to) continue;
maxto[now]=max(maxto[now],maxto[to]);
}
}
}
inline void lca_init(){
repin(i,1,n){
f[i][0]=fa[i];
}
for(int j=1;1<<j<=maxidep;j++){
repin(i,1,n){
f[i][j]=-1;
if(f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1];
}
}
}
inline int lca_query(int x,int y){
if(x==y) return x;
if(dep[x]<dep[y]) swap(x,y);
int log;
for(log=0;1<<log<=dep[x];log++);
for(int j=log-1;j>=0;j--){
if(f[x][j]!=-1 && dep[f[x][j]]>=dep[y]) x=f[x][j];
}
if(x==y) return x;
for(log=0;1<<log<=dep[x];log++);
for(int j=log-1;j>=0;j--){
if(f[x][j]!=f[y][j]){
x=f[x][j];
y=f[y][j];
}
}
return fa[x];
}
#define lch (id<<1)
#define rch (id<<1|1)
#define mid ((l+r)>>1)
int val[MAXN];
struct Segment_Tree{
int sum,realsum;
int lazy;
}tree[MAXN<<2];
inline void plant_tree(int id,int l,int r){
tree[id].lazy=-1;
tree[id].realsum=0;
if(l==r){
tree[id].sum=val[rvto[l]];
return;
}
plant_tree(lch,l,mid);
plant_tree(rch,mid+1,r);
tree[id].sum=tree[lch].sum+tree[rch].sum;
}
inline void pushdown(int id){
if(tree[id].lazy!=-1){
tree[lch].lazy=tree[id].lazy;
tree[lch].realsum=tree[id].lazy*tree[lch].sum;
tree[rch].lazy=tree[id].lazy;
tree[rch].realsum=tree[id].lazy*tree[rch].sum;
tree[id].lazy=-1;
}
}
inline void update(int id,int ql,int qr,int l,int r,int val){
if(ql==l && qr==r){
tree[id].lazy=val;
tree[id].realsum=val*tree[id].sum;
return;
}
pushdown(id);
if(qr<=mid) update(lch,ql,qr,l,mid,val);
else if(mid<ql) update(rch,ql,qr,mid+1,r,val);
else{
update(lch,ql,mid,l,mid,val);
update(rch,mid+1,qr,mid+1,r,val);
}
tree[id].realsum=tree[lch].realsum+tree[rch].realsum;
}
inline void jumptoto(int x,int aim){
while(dep[x]>=dep[aim]){
if(dep[upto[x]]<=dep[aim]){
update(1,vto[aim],vto[x],1,n,1);
break;
}
update(1,vto[upto[x]],vto[x],1,n,1);
x=fa[upto[x]];
}
}
inline void jumpto(int x,int y){
if(x==y){
update(1,vto[x],vto[x],1,n,1);
return;
}
int an=lca_query(x,y);
if(x==an) jumptoto(y,an);
else if(y==an) jumptoto(x,an);
else{
jumptoto(y,an);
jumptoto(x,an);
return;
}
}
int main(){
int T=read(),Q;
while(T--){
n=read();
for(int i=1;i<=n;i++){
val[i]=read();
head[i]=-1;
}
num_edge=0;
for(int i=1;i<=n-1;i++){
int u,v;
u=read(),v=read();
add_Edge(u,v);
add_Edge(v,u);
}
dfs1();
dfs2();
lca_init();
plant_tree(1,1,n);
Q=read();
while(Q--){
int ty;
ty=read();
if(ty==1){
int a,b;
a=read(),b=read();
jumpto(a,b);
}
else if(ty==2){
int x;
x=read();
update(1,vto[x],vto[x],1,n,0);
}
else if(ty==3){
int x;
x=read();
update(1,vto[x],maxto[x],1,n,1);
}
printf("%d\n",tree[1].realsum);
}
}
return 0;
}