隔了2天终于写完了。
前置知识:树剖。
思路:
我们先看一下一个数字连续取模多个数字要怎么办?
采用暴力法一个个算肯定是不可取的,如果我们认真观察就会发现对于 a a a m o d mod mod b b b 来说当 a < b a < b a<b 时,取模结果依然是 a a a 。所以每次取模完只需要找出下一个小于 a a a的模数取模即可。尽管我一开始就想到这个方法,但是我以为这样会超时,知道我看到了某篇题解后才发现,当一个数被一个小于它的数取模完之后结果必然小于原数的一半,也就是说取模次数不超过 log 2 n \log_2n log2n 次(n为被取模数字),如果用树剖去做时间复杂度只是 O ( q log 2 n log 2 x ) O(q\log_2n\log_2x) O(qlog2nlog2x)。
知道了如何取模操作之后剩下的就全是树剖模板了,只需维护一棵线段树用来查找一段区间第一个小于或大于 x x x 的数即可。
值得注意得是取模没有交换律,所以得要老老实实的把 u u u 和 v v v 跳过的区间分别存贮存起来。
代码
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,deep[200005],q,c[200005],SIZE[200005],son[200005],father[200005],dfscnt,id[200005],top[200005],HASH[200005],MIN[800005];
vector<int>e[200005];
void dfs_1(int u,int fa){
father[u]=fa;
SIZE[u]=1;
deep[u]=deep[fa]+1;
for(size_t i=0;i<e[u].size();i++){
int v=e[u][i];
if(v==fa)continue;
dfs_1(v,u);
SIZE[u]+=SIZE[v];
if(SIZE[v]>SIZE[son[u]])
son[u]=v;
}
}
void dfs_2(int u,int topx){
top[u]=topx;
id[u]=++dfscnt;
HASH[dfscnt]=u;
if(!son[u]) return;
dfs_2(son[u],topx);
for(size_t i=0;i<e[u].size();i++){
int v=e[u][i];
if(v==father[u]||v==son[u])continue;
dfs_2(v,v);
}
}
void build(int l,int r,int k){
if(l==r){
MIN[k]=c[HASH[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
MIN[k]=min(MIN[2*k],MIN[2*k+1]);
}
int find_front(int L,int R,int x,int l,int r,int k){
if(l==r)return MIN[k];
int mid=(l+r)/2,res=0;
if(L<=mid&&MIN[2*k]<=x) res=find_front(L,R,x,l,mid,2*k);
if(R>=mid+1&&MIN[2*k+1]<=x&&res==0) return find_front(L,R,x,mid+1,r,2*k+1);
return res;
}
int find_back(int L,int R,int x,int l,int r,int k){
if(l==r){
return MIN[k];
}
int mid=(l+r)/2,res=0;
if(R>=mid+1&&MIN[2*k+1]<=x) res=find_back(L,R,x,mid+1,r,2*k+1);
if(L<=mid&&MIN[2*k]<=x&&res==0) return find_back(L,R,x,l,mid,2*k);
return res;
}
struct node{
int l,r;
};
int query(int u,int v,int x){
vector<node>qu;
vector<node>qv;
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]]){
qv.push_back({id[top[v]],id[v]});
v=father[top[v]];
}else{
qu.push_back({id[top[u]],id[u]});
u=father[top[u]];
}
}
if(id[u]<id[v])qv.push_back({id[u],id[v]});
else qu.push_back({id[v],id[u]});
for(int i=0;i<qu.size();i++){
int l=qu[i].l,r=qu[i].r;
while(1){
int mod=find_back(l,r,x,1,n,1);
if(mod==0)break;
x%=mod;
}
}
for(int i=qv.size()-1;i>=0;i--){
int l=qv[i].l,r=qv[i].r;
while(1){
int mod=find_front(l,r,x,1,n,1);
if(mod==0)break;
x%=mod;
}
}
return x;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;i++)
cin>>c[i];
dfs_1(1,1);
dfs_2(1,1);
build(1,n,1);
while(q>0){
q--;
int u,v,x;
cin>>u>>v>>x;
cout<<query(u,v,x)<<endl;
}
return 0;
}