\(\text{Solution}\)
第一眼看见这道题,以为就是 \(\text{CodeForces - 519E A and B and Lecture Rooms}\) 稍微变一变。
然而,\(w_{edge}\le 1e18\)。当场挂掉。
不过,除与乘自有它的好处。我们发现 \(y\le 1e18\),那其实询问只能走 \(\log(1e18)\) 次权值大于 \(1\) 的边(这个数约等于 \(60\))。题目中还有一个重要的条件:\(1<c_i<x_{p_i}\),也就是说一条边的权值为 \(1\) 时就不会再被更改。
我们用冰茶姬将权值为 \(1\) 的一段边缩起来,然后暴力一个个除过去就行了。
\(\text{Code}\)
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,head[N],nxt[N<<1],to[N<<1],cnt,fa[N],f[N][22],dep[N];
ll Val[N<<1],val[N];
ll read() {
ll x=0,f=1; char s;
while((s=getchar())>‘9‘||s<‘0‘) if(s==‘-‘) f=-1;
while(s>=‘0‘&&s<=‘9‘) x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
void addEdge(int u,int v,ll w) {
nxt[++cnt]=head[u],to[cnt]=v,head[u]=cnt,Val[cnt]=w;
}
void init() {for(int i=1;i<=n;++i) fa[i]=i;}
int Find(int x) {return x==fa[x]?x:fa[x]=Find(fa[x]);}
void dfs(int u,int ba) {
dep[u]=dep[ba]+1; f[u][0]=ba;
for(int i=1;i<=20;++i) f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(v==ba) continue;
if(Val[i]==1) fa[v]=Find(u);
val[v]=Val[i];
dfs(v,u);
}
}
int jump(int u,int d) {
int x=u;
for(int i=20;i>=0;--i) if(dep[x]-dep[f[u][i]]<=d) u=f[u][i];
return u;
}
int LCA(int u,int v) {
if(dep[v]>dep[u]) swap(u,v);
u=jump(u,dep[u]-dep[v]);
if(u==v) return u;
for(int i=20;i>=0;--i)
if(f[u][i]^f[v][i]) {
u=f[u][i]; v=f[v][i];
}
return f[u][0];
}
int main() {
int u,v,op,x[N],y[N]; ll w;
n=read(),m=read();
for(int i=1;i<n;++i) {
u=read(),v=read(),w=read();
addEdge(u,v,w); addEdge(v,u,w);
x[i]=u,y[i]=v;
}
init(); dfs(1,0);
while(m--) {
op=read(),u=read();
if(op==1) {
v=read(),w=read();
int lca=LCA(u,v);
while(dep[u]>dep[lca]&&w) {
if(val[u]!=1) w/=val[u];
u=Find(f[u][0]);
}
while(dep[v]>dep[lca]&&w) {
if(val[v]!=1) w/=val[v];
v=Find(f[v][0]);
}
printf("%lld\n",w);
}
else {
w=read();
v=x[u],u=y[u];
if(f[u][0]==v) swap(u,v);
val[v]=w;
if(w==1) fa[v]=Find(u);
}
}
return 0;
}