赛码"BestCoder"杯中国大学生程序设计冠军赛1008(hdu5221)树链剖分点权

来源:互联网 发布:php try catch 编辑:程序博客网 时间:2024/06/08 06:32

Occupation

Accepts: 22
Submissions: 104
Time Limit: 12000/6000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
Problem Description

Miceren finds a huge country named HY. HY has N cities numbered from 1 to N connected by N  1 bidirectional roads. There exists a path between any two cities.

It can be imagined as a tree with n vertices rooted at vertex 1.

Miceren wants to occupy some cities here. Each city has a value vi. (Notice that the value of a city may be negative. Nevertheless, Miceren wants to occupied this city.)

As some usual stories, someone named Cloud wants to "steal" some cities from Miceren.

At the beginning, Miceren and Cloud don't occupy any city.

In the following Q days, one of three events may happen

  1. Miceren will walk from the a-th city to the b-th city and all cities visited in this trip will belong to Miceren. (1  a,b  N)

  2. Cloud will steal the x-th city. If Miceren occupied the x-th city before, Miceren will lost the control of this city. (1  x  N)

  3. Miceren will occupy the subtree rooted at x.(1  x  N)

As Miceren's friend, you must tell Miceren the total value of all cities which belong to Miceren after each day.

Input

The first line contains a single integer T, indicating the number of test cases.

Each test case begin with one integer N, indicating the number of cities in HY.

The next line contains N integer Vi, indicating the value of each city.

The next N  1 lines contain the details of the roads. Each line contains two integers u, v meaning that there is a road between cities u and v.

The next line contains one integer Q.

The next Q lines contain the details of event. If the format is "1 a b", it means the first event happened where Miceren walks from a-th city to b-th city. If the format is “2 x”, it means the second event happened where Cloud "steal"s the x-th city. Otherwise the format is “3 x” and the third event happened where Micron occupied the subtree rooted at x.

T is about 100.

1  N  100000.

1000  Vi  1000.

The ratio of test cases with N > 100 is less than 5%.

Output

For each test queries, print the answer.

Sample Input
1101 2 3 4 5 6 7 8 9 10 1 21 32 42 55 95 103 63 73 861 10 41 9 72 53 42 41 6 10
Sample Output
214136363243
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.


比赛的时候也没时间看这个题,突然发现好简单的树链剖分

对于操作一,只需要对区间做一个标记,表示他是M的,然后更新属于M的城市的val

对于操作二,跟操作一一样,只不过是把这个城市从M中去除

对于操作三,因为对于以x为根的子树和x在 线段树中是连续的,所以,根据树链剖分预处理出的num(子孙个数,包括这一点)对整个区间进行更新就可以了

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int maxn=100010;int N,M;int val[maxn];int head[maxn],tot,pos;int son[maxn];int num[maxn];int dep[maxn];int fa[maxn];int w[maxn],fw[maxn];int top[maxn];struct node{int v,next;}edge[maxn*2];void init(){tot=pos=0;memset(head,-1,sizeof(head));memset(son,-1,sizeof(son));}void add_edge(int u,int v){edge[tot].v=v;edge[tot].next=head[u];head[u]=tot++;}void dfs1(int u,int f,int depth){fa[u]=f;dep[u]=depth;num[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==f)continue;dfs1(v,u,depth+1);num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;}}void dfs2(int u,int sp){top[u]=sp;w[u]=++pos;fw[pos]=u;if(son[u]!=-1)dfs2(son[u],sp);for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v!=fa[u]&&v!=son[u])dfs2(v,v);}}struct IntervalTree{int sum[maxn<<2];int setv[maxn<<2];int active[maxn<<2];void build(int o,int l,int r){sum[o]=setv[o]=active[o]=0;if(l==r){sum[o]=val[fw[l]];return ;}int mid=(l+r)>>1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);sum[o]=sum[o<<1]+sum[o<<1|1];}void update(int o,int l,int r,int q1,int q2,int x){if(q1<=l&&r<=q2){setv[o]=x;if(setv[o])active[o]=sum[o];else active[o]=0;return ;}pushdown(o);int mid=(l+r)>>1;if(q1<=mid)update(o<<1,l,mid,q1,q2,x);if(q2>mid)update(o<<1|1,mid+1,r,q1,q2,x);active[o]=active[o<<1]+active[o<<1|1];}void pushdown(int o){if(setv[o]){setv[o<<1]=setv[o<<1|1]=setv[o];if(setv[o<<1])active[o<<1]=sum[o<<1];else active[o<<1]=0;if(setv[o<<1|1])active[o<<1|1]=sum[o<<1|1];else active[o<<1|1]=0;setv[o]=0;}}}tree;void MChange(int l,int r){int f1=top[l],f2=top[r];while(f1!=f2){if(dep[f1]<dep[f2]){swap(l,r);swap(f1,f2);}tree.update(1,1,N,w[f1],w[l],1);l=fa[f1],f1=top[l];}if(dep[l]>dep[r])swap(l,r);tree.update(1,1,N,w[l],w[r],1);}int main(){int T,u,v;scanf("%d",&T);while(T--){scanf("%d",&N);init();for(int i=1;i<=N;i++)scanf("%d",&val[i]);for(int i=1;i<N;i++){scanf("%d%d",&u,&v);add_edge(u,v);add_edge(v,u);}dfs1(1,0,0);dfs2(1,1);tree.build(1,1,N);scanf("%d",&M);int op,x,y;while(M--){scanf("%d",&op);if(op==1){scanf("%d%d",&x,&y);MChange(x,y);}else if(op==2){scanf("%d",&x);tree.update(1,1,N,w[x],w[x],0);}else{scanf("%d",&x);tree.update(1,1,N,w[x],w[x]+num[x]-1,1);}printf("%d\n",tree.active[1]);}}return 0;}




0 0
原创粉丝点击