【模拟试题】花园

【模拟试题】花园

Description

  小豪有一个花园,里面有n个花棚,编号1..n,每个花棚里有一定数量的花a i 。小豪花园的路十分神奇,可以使得任意两个花棚之间仅有一条最短路,即形成树结构,其中根节点是1号花棚。现在小豪打算修缮一下他的花园,重新分配每个花棚里花的数量。为了能方便快捷地知道花园的情况,小豪现在需要你的帮助。具体地说,小豪共有m个操作。操作有三种:
  1. 1 u k 表示如果一个花棚在以u号花棚为根的子树中,那么小豪会把这个花棚花的数量模k
  2. 2 u x 表示小豪将u号花棚花的数量变成x
  3. 3 u v 表示小豪询问从u号花棚走到v号花棚总共能看到的花的数量
  你能帮助小豪吗?

Input

  第一行有两个正整数n和m,代表花棚的数量和小豪操作的个数。
  接下来n−1行,每行两个正整数u,v(1 ≤ u,v ≤ n,u 6= v),表示u号花棚与v号花棚直接有路相连。
  下一行有n个非负整数a 1 ,a 2 ,...,a n ,表示起始时每个花棚中花的数量。
  接下来m行,一行表示一个操作,格式如题所述。(可参考样例)

Output

  对于每个操作3输出一行一个整数表示结果。                                                                                                                        

Sample Input

8 7
1 2
2 3
2 4
2 5
1 6
6 7
6 8
1 2 3 4 5 6 7 8
3 3 6
1 2 3
2 2 4
3 4 8
2 3 11
1 1 5
3 3 7                                                                                                                                                                                                                                                

Sample Output

12
20
9                                                                                                                                                                                                                                                

Hint

【数据范围】
  对于20%的数据,n,m ≤ 2000
  另外10%的数据,所有花棚构成一条链,且无操作1
  另外20%的数据,无操作1
  对于100%的数据,n,m ≤ 100000, ai ,x,k ≤ 10^8 , k ≥ 1                                                                                                                        

Solution

树链剖分
三个操作:
        1.对子树取模
        2.对单点修改
3.对路径询问
完成剖分之后,对于操作一,我们直接暴力修改对应的线段树上的区间。通过维护区间max来判断这个区间是否
需要取模。另外两个就是标准的树剖操作了。 

CODE

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline long long read(){
	char c;long long rec=0;
	while((c=getchar())<'0'||c>'9');
	while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
	return rec;
}
long long n,m;
struct Branch {long long next,to;}branch[200005];
long long h[100005],cnt=0;
inline void add(long long x,long long y){branch[++cnt].to=y;branch[cnt].next=h[x];h[x]=cnt;return ;}
long long c[100005];
long long size[100005],deep[100005];
long long top[100005],fa[100005],son[100005];
long long id[100005],pos[100005],low[100005];
inline void Dfs1(long long v,long long pre,long long dep){
	size[v]=1;fa[v]=pre;deep[v]=dep;
	for(long long i=h[v];i;i=branch[i].next){
		long long j=branch[i].to;
		if(j==pre)continue;
		Dfs1(j,v,dep+1);size[v]+=size[j];
		if(size[son[v]]<size[j])son[v]=j;
	}return ;
}
inline void Dfs2(long long v,long long T){
	if(v==0)return ;
	top[v]=T;id[v]=++cnt;pos[cnt]=v;
	Dfs2(son[v],T);
	for(long long i=h[v];i;i=branch[i].next){
		long long j=branch[i].to;
		if(j==fa[v]||j==son[v])continue;
		Dfs2(j,j);
	}low[v]=cnt;return ;
}
struct Seg_Tree{long long L,R,val,maxx;}tree[100005<<2];
inline void Pushup(long long v){
	tree[v].val=tree[v<<1].val+tree[v<<1|1].val;
	tree[v].maxx=max(tree[v<<1].maxx,tree[v<<1|1].maxx);
	return ;
}
inline void Build(long long v,long long L,long long R){
	tree[v].L=L;tree[v].R=R;
	if(L==R){tree[v].val=tree[v].maxx=c[pos[L]];return ;}
	long long mid=(L+R)>>1;
	Build(v<<1,L,mid);Build(v<<1|1,mid+1,R);
	Pushup(v);return ;
}
inline void Mod(long long v,long long x){
    if(tree[v].maxx<x)return ;
    if(tree[v].L==tree[v].R){tree[v].maxx%=x;tree[v].val%=x;return ;}
    Mod(v<<1,x);Mod(v<<1|1,x);
    Pushup(v);
	return ;
}
inline void Change(long long v,long long L,long long R,long long x){
	if(tree[v].L>R||tree[v].R<L)return ;
	if(tree[v].L>=L&&tree[v].R<=R){Mod(v,x);return ;}
	Change(v<<1,L,R,x);Change(v<<1|1,L,R,x);
	Pushup(v);return ;
}
inline void Modify(long long v,long long k,long long x){
	if(tree[v].L>k||tree[v].R<k)return ;
	if(tree[v].L==tree[v].R){tree[v].maxx=tree[v].val=x;return ;}
	Modify(v<<1,k,x);Modify(v<<1|1,k,x);
	Pushup(v);return ;
}
inline long long Ask(long long v,long long L,long long R){
	if(tree[v].L>R||tree[v].R<L)return 0;
	if(tree[v].L>=L&&tree[v].R<=R)return tree[v].val;
	return Ask(v<<1,L,R)+Ask(v<<1|1,L,R);
}
int main(){
	n=read();m=read();
	for(long long i=1;i<n;i++){
		long long x=read(),y=read();
		add(x,y);add(y,x);
	}cnt=0;
	for(long long i=1;i<=n;i++)c[i]=read();
	Dfs1(1,0,1);Dfs2(1,1);
	Build(1,1,n);
	for(long long i=1;i<=m;i++){
		long long f=read(),x=read(),y=read();
		if(f==1)Change(1,id[x],low[x],y);
		if(f==2)Modify(1,id[x],y);
		if(f==3){
			long long ans=0;
			while(top[x]!=top[y]){
				if(deep[top[x]]<deep[top[y]])swap(x,y);
				ans+=Ask(1,id[top[x]],id[x]);
				x=fa[top[x]];
			}if(deep[x]<deep[y])swap(x,y);
			ans+=Ask(1,id[y],id[x]);
			cout<<ans<<'\n';		
		}
	}
	return 0;
}
注意点的编号与线段树中的编号对应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值