题意:有三种操作,1代表占领u-v这条路径上的所有点,2表示失去u这个点,3占领以u为根的子树的所有点。。对每一个询问输出他占领城市的权值之和。。
首先树链剖分处理一下,然后用线段树维护区间求和区间查询就好了,查询过的点再置0。。。
处理子树可以根据dfs序来求,可以在树链剖分的时候记录下这个点的dfs序,然后查询子树就可以直接有一个区间了。
1操作没有想到处理一个点的时候错了。。wa了几次
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int MAXN=100010;
int fa[MAXN],w[MAXN],siz[MAXN],son[MAXN],dep[MAXN],top[MAXN],in[MAXN],out[MAXN];
int w1[MAXN];
int totw,dfs_clock;
struct EDGE
{
int v,next;
}edge[MAXN<<1];
int head[MAXN],size;
void init()
{
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
memset(fa,-1,sizeof(fa));
memset(dep,0,sizeof(dep));
size=0;
totw=0;
dfs_clock=0;
}
void add_edge(int u,int v)
{
edge[size].v=v;
edge[size].next=head[u];
head[u]=size++;
}
void dfs1(int u,int f,int deep) //dfs求出siz,son,fa,dep
{
siz[u]=1;
int mmax=-1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==f)
continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v,u,deep+1);
siz[u]+=siz[v];
if(siz[v]>mmax)
{
mmax=siz[v];
son[u]=v;
}
}
}
void dfs2(int u,int f) //求出w,top
{
in[u]=++dfs_clock;
top[u]=f;
totw++;
w[u]=totw;
w1[totw]=u;
if(son[u]!=-1)
dfs2(son[u],f);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
out[u]=dfs_clock;
}
int val[MAXN];
struct TREE
{
int l,r;
int sum;
int mark,val;
int mid()
{
return (l+r)>>1;
}
}tree[MAXN<<2];
void pushup(int k)
{
tree[k].sum=tree[ls].sum+tree[rs].sum;
}
void pushdown(int k)
{
if(tree[k].mark!=-1)
{
tree[ls].sum=tree[rs].sum=tree[k].val;
tree[ls].val=tree[rs].val=tree[k].val;
tree[ls].mark=tree[rs].mark=tree[k].mark;
tree[k].mark=-1;
}
}
void build(int l,int r,int k)
{
tree[k].l=l;
tree[k].r=r;
tree[k].mark=-1;
tree[k].val=0;
if(l==r)
{
tree[k].sum=val[w1[l]];
return;
}
int mid=tree[k].mid();
build(l,mid,ls);
build(mid+1,r,rs);
pushup(k);
}
void update(int l,int r,int k,int v)
{
if(tree[k].l>=l&&tree[k].r<=r)
{
tree[k].sum=v;
tree[k].val=v;
tree[k].mark=0;
return;
}
pushdown(k);
int mid=tree[k].mid();
if(r<=mid)
update(l,r,ls,v);
else if(l>mid)
update(l,r,rs,v);
else
{
update(l,mid,ls,v);
update(mid+1,r,rs,v);
}
pushup(k);
}
int query(int l,int r,int k)
{
if(tree[k].l>=l&&tree[k].r<=r)
return tree[k].sum;
pushdown(k);
int mid=tree[k].mid();
if(r<=mid)
return query(l,r,ls);
else if(l>mid)
return query(l,r,rs);
else
return query(l,mid,ls)+query(mid+1,r,rs);
}
int ans;
void update1(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans+=query(w[top[x]],w[x],1);
update(w[top[x]],w[x],1,0);
x=fa[top[x]];
}
if(x==y)
{
ans+=query(w[x],w[x],1);
update(w[x],w[x],1,0);
return;
}
if(dep[x]>dep[y])
swap(x,y);
ans+=query(w[x],w[y],1);
update(w[x],w[y],1,0);
}
void update2(int u)
{
if(query(w[u],w[u],1)==0)
{
update(w[u],w[u],1,val[u]);
ans-=val[u];
}
}
void update3(int x)
{
int l=in[x];
int r=out[x];
ans+=query(l,r,1);
update(l,r,1,0);
}
int main()
{
int t,n,i;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
init();
int u,v;
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
int q;
dfs1(1,-1,0);
dfs2(1,1);
build(1,totw,1);
scanf("%d",&q);
ans=0;
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&u,&v);
update1(u,v);
}
else if(op==2)
{
scanf("%d",&u);
update2(u);
}
else
{
scanf("%d",&u);
update3(u);
}
printf("%d\n",ans);
}
}
return 0;
}
/*
2
7
1 2 3 4 5 6 7
1 2
2 3
3 6
3 7
3 4
4 5
100
*/