problem
在一个平面上有n个齿轮,每个齿轮都有自己的初始半径
ri
。有n-1对齿轮是互相嵌在一起的,即它们拥有相同的线速度。如果将n个齿轮当作n个点,将n-1条相嵌关系当作n-1条边,那么这些齿轮会组成一个树。即树上每条边连接的两个点代表的齿轮拥有相同的线速度。
现在有两种操作:
——操作1:将第x个齿轮的半径改成y
——操作2:如果给第x个齿轮一个角速度y,那么所有齿轮都旋转了起来,问所有齿轮中,角速度最大的是多少。
本题中,所有齿轮的半径以及角速度都是2的正整数次幂。
在此题中,你不需要考虑和某个齿轮嵌套的其它齿轮会发生冲突挤压。
Input
第一行两个整数n,m(1<=n<=200000,1<=m<=200000),分别表示齿轮的个数以及操作的个数。
第二行n个整数
ri
,表示每个齿轮的初始半径。(1<=
ri
<=
230
,且
ri
=
2k
)
接下来n-1行,每行两个整数x,y,表示第x个齿轮与第y个齿轮具有相同的线速度。
接下来m行描述m个操作(op,x,y)
若op=1则表示操作1,将第x个齿轮的半径改成y(1<=y<=
230
,且y=
2k
)
若op=2则表示操作2,给第x个齿轮一个角速度y(1<=y<=
230
,且y=
2k
)
Output
对于每个操作2,输出最大的角速度。
数据保证最大的角速度一定是整数,但有可能会比较大,所以输出答案对
109
+7取模
Input
3 3
4 2 8
1 2
1 3
2 1 2
1 2 4
2 2 1
Output
4
1
Limitation
1s 256MB
Hint
对于操作1,第1个齿轮的角速度是2,第2个齿轮角速度是4,第3个齿轮角速度是1
对于操作3,第1个齿轮的角速度是1,第2个齿轮角速度是1,第3个齿轮角速度是
12
传送门传送门传送门传送门
思路
角速度最大的齿轮即为半径最小的齿轮,因为每次旋转它们的线速度相同
比赛时我是用dfs序映射到线段树,然后线段树维护的。
不dfs序也行,因为和边、子树好像没有什么关系,只涉及到半径的修改和最小半径的查找
代码示例
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=200100;
const long long inf=3e18;
struct Edge{
int from,to;
}edges[maxn<<1];
int head[maxn<<1],in[maxn],out[maxn],Hash[maxn];
int Clock,cnt;
ll rr[maxn<<2],val[maxn];//rr线段树维护最小值
//ll lazy[maxn<<2]; 单点修改
//val是齿轮的半径
void edge_add(int u,int v){
edges[cnt].from=v;
edges[cnt].to=head[u];
head[u]=cnt++;
}
void init(){
memset(head,-1,sizeof(head));
cnt=0;
Clock=0;
}
void dfs(int rt,int f){
in[rt]=++Clock;
Hash[Clock]=rt;//这个编号的齿轮就对应着这个rt结点
//有了这个就能利用线段树找价值了
for(int i=head[rt];i!=-1;i=edges[i].to){
int tt=edges[i].from;
if(tt!=f) dfs(tt,rt);
}
out[rt]=Clock;
}
void PushUp(int rt){
rr[rt]=min(rr[rt<<1],rr[rt<<1|1]);
}
void build(int l,int r,int rt){
rr[rt]=inf;//赋大值
if(l==r){
rr[rt]=val[Hash[l]];
return ;
}
int m=(l+r)>>1;
build(lson); build(rson);
PushUp(rt);
}
void update(int p,ll cov,int l,int r,int rt){
//p点需要修改为cov这个新的半径
if(l==r){
rr[rt]=cov;//这里是赋值
return ;
}
int m=(l+r)>>1;
if(p<=m) update(p,cov,lson);
else update(p,cov,rson);
PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R) return rr[rt];
int m=(l+r)>>1;
ll ret=inf;//很大数
if(L<=m) ret=min(ret,query(L,R,lson));//维护最值
if(R>m) ret=max(ret,query(L,R,rson));
return ret;
}
int main()
{
ios::sync_with_stdio(false);
//freopen("read.txt","r",stdin);
int n,m;//n个点,m个操作
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>val[i];
}
init();
int u,v,op;
for(int i=0;i<n-1;++i){
cin>>u>>v;
edge_add(u,v);
edge_add(v,u);
}
dfs(1,0);
build(1,Clock,1);
for(int i=0;i<m;++i){
cin>>op;
if(op==1){
int p;
ll cov;
cin>>p>>cov;
update(in[p],cov,1,Clock,1);
val[p]=cov;
}
else{
int p;
ll cov;//角速度
cin>>p>>cov;
ll xian=val[p]*cov;
ll minr=query(1,Clock,1,Clock,1);
//cout<<xian<<" 线速度"<<endl;
//cout<<minr<<" 最小半径"<<endl;
cout<<(xian/minr)%mod<<endl;
}
}
return 0;
}