【NOIP】test

【題目背景】

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));
		}
		
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章