【模拟试题】花园
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号花棚总共能看到的花的数量
你能帮助小豪吗?
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行,一行表示一个操作,格式如题所述。(可参考样例)
接下来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
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
20
9
Hint
【数据范围】
对于20%的数据,n,m ≤ 2000
另外10%的数据,所有花棚构成一条链,且无操作1
另外20%的数据,无操作1
对于100%的数据,n,m ≤ 100000, ai ,x,k ≤ 10^8 , k ≥ 1
对于20%的数据,n,m ≤ 2000
另外10%的数据,所有花棚构成一条链,且无操作1
另外20%的数据,无操作1
对于100%的数据,n,m ≤ 100000, ai ,x,k ≤ 10^8 , k ≥ 1
Solution
树链剖分
三个操作:
1.对子树取模
2.对单点修改
3.对路径询问
完成剖分之后,对于操作一,我们直接暴力修改对应的线段树上的区间。通过维护区间max来判断这个区间是否
需要取模。另外两个就是标准的树剖操作了。
三个操作:
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;
}
注意点的编号与线段树中的编号对应。