【題目背景】
Tom在學寫動態樹,但是做題時過了樣例,提交RE。Tom抓住Jerry要他寫個暴力來對拍。Jerry覺得這任務太簡單了,就讓你來完成一下。
【題目描述】
有一棵n個節點的樹,初始時根節點爲1。現在要支持如下操作——1、將某節點設置爲根;2、改變某節點權值;3、詢問以某節點爲根的子樹內節點權值之和;4、詢問以某兩點 爲端點的鏈上的節點權值之和。
【輸入格式】
第一行兩個正整數n和q,表示樹的節點數和操作個數。
接着n-1行每行兩個整數u和v,表示有連接u和v的一條邊。
隨後一行n個正整數,表示每個點的初始權值。
之後q行每行格式如下:
首先一個範圍爲1~4的正整數,表示該操作類型。
對於1操作,之後一個正整數x,表示將x節點設置爲根。
對於2操作,之後兩個正整數x和v,表示將x節點的權值改爲v。
對於3操作,之後一個正整數x,表示詢問以x爲根的子樹內節點權值之和。
對於4操作,之後兩個正整數x和y,表示詢問以x和y爲端點的鏈上的節點權值之和。
【輸出格式】
對於每個操作3和操作4,輸出一行一個整數表示詢問的答案。
【輸入樣例1】
3 3
1 2
2 3
3 2 1
3 1
1 2
3 1
【輸出樣例1】
6
3
【輸入樣例2】
1 3
1
4 1 1
2 1 2
4 1 1
【輸出樣例2】
1
2
題解:
裸的樹鏈剖分,最後重新記錄換了根對答案的影響
#include<bits/stdc++.h>
using namespace std;
int n,q;
int head[200005];
int next[200005];
int ver[200005];
int tot,cnt;
int size[100005];
int zson[100005];
int d[100005];
int id[100005];
int fa[100005];
int top[100005];
int val[100005];
int nowval[100005];
int tree[400005];
int root,calc;
int read(){
int num=0;
char ch=getchar();
while(ch>'9'||ch<'0'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<1)+(num<<3)+ch-'0';
ch=getchar();
}
return num;
}
void add(int x,int y){
ver[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int fat,int deep){
size[x]=1;
fa[x]=fat;
d[x]=deep;
for(int i=head[x];i;i=next[i]){
if(ver[i]==fat) continue;
dfs1(ver[i],x,deep+1);
size[x]+=size[ver[i]];
if(size[ver[i]]>size[zson[x]]){
zson[x]=ver[i];
}
}
}
void dfs2(int x,int topp){
id[x]=++cnt;
nowval[cnt]=val[x];
top[x]=topp;
if(!zson[x]) return;
dfs2(zson[x],topp);
for(int i=head[x];i;i=next[i]){
if(ver[i]==zson[x] || ver[i]==fa[x])continue;
dfs2(ver[i],ver[i]);
}
}
void build(int node,int l,int r){
if(l==r){
tree[node]=nowval[l];
return;
}
int mid=(l+r)>>1;
build(node<<1,l,mid);
build((node<<1)|1,mid+1,r);
tree[node]=tree[node<<1]+tree[(node<<1)|1];
}
void update(int node,int l,int r,int goal,int v){
if(l==r){
calc=tree[node];
tree[node]=v;
return;
}
int mid=(l+r)>>1;
if(goal<=mid){
update(node<<1,l,mid,goal,v);
}
else update((node<<1)|1,mid+1,r,goal,v);
tree[node]=tree[node]-calc+v;
}
int check(int x,int y){
if(x==y)return -1;
if(d[x]>d[y])return 0;
while(d[x]<=d[y]){
if(fa[y]==x)
return y;
y=fa[y];
}
return 0;
}
void work(int now,int l,int r,int L,int R){
if(l>=L && r<=R){
calc+=tree[now];
return;
}
else{
int mid=(l+r)>>1;
if(L<=mid)
work(now<<1,l,mid,L,R);
if(R>mid)
work((now<<1)|1,mid+1,r,L,R);
}
}
int hhh(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
calc=0;
work(1,1,n,id[top[x]],id[x]);
ans+=calc;
x=fa[top[x]];
}
if(d[x]>d[y]) swap(x,y);
calc=0;
work(1,1,n,id[x],id[y]);
ans+=calc;
return ans;
}
int main(){
n=read(),q=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
val[i]=read();
size[0]=-1;
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
int k,x,v,y;
for(int i=1;i<=q;i++){
k=read();
if(k==1){
root=read();
continue;
}
if(k==2){
x=read(),v=read();
update(1,1,n,id[x],v);
continue;
}
if(k==3){
x=read();
int q=check(x,root);
if(q==0){
calc=0;
work(1,1,n,id[x],id[x]+size[x]-1);
printf("%d\n",calc);
continue;
}
if(q==-1){
calc=0;
work(1,1,n,id[1],id[1]+size[1]-1);
printf("%d\n",calc);
continue;
}
calc=0;
work(1,1,n,id[1],id[1]+size[1]-1);
int num1=calc;
calc=0;
work(1,1,n,id[q],id[q]+size[q]-1);
printf("%d\n",num1-calc);
continue;
}
if(k==4){
x=read();
y=read();
printf("%d\n",hhh(x,y));
}
}
}