题意:
给定一棵无根树,每条边有边权。
两种操作。
第一种询问给定值
y(<=1018)
除以点u到点v的所有边的边权的值,注意每一次除都是下取整。
第二种是修改某边边权,并且每一次修改后该边边权相对原来一定减小。
边权为正整数
(<=1018)
n<=2∗105
,询问次数
m<=2∗105
解析:
sb cin害我T了好几发。
首先
(a/b)/c
是否等于
a/(b∗c)
,除法都是下取整。
反正我暴力拍1~1000没拍出来不等于的。
那暂且认为这是对的。
如果没有操作2
我们显然可以利用倍增来强行搞这道题。
mul[x][i]
表示
x
到
由于会爆
longlong
所以可以考虑转成
double
型。
总复杂度
O(nlogn+mlogn)
那么如果有操作2呢。
显然暴力重构
mul
数组会T成渣渣。
这个方法直接GG。
所以需要换一个思路。
我们发现
1018
至多除以60个2之后就变成了0。
这说明如果边权全部大于1的话。
我们只需要找到
u,v
的
lca
,之后暴力向上除就可以了,如果除了60次以上或者没到60次val就已经变成0的话,那么直接返回0即可。
那么修改呢?直接改边就可以了。
如果边权有等于1的怎么办。
因为图是一棵树,所以显然我们可以路径压缩边权为1的边。
查询向上搜的时候直接找祖先即可。
那么有修改呢?
因为修改一定是把边减小,所以如果减成1了,那么继续压缩一下路径,否则直接修改。
所以这题就可以在O(并查集*m*logn)内解决了。
那么如果修改操作不限定一定减小边权呢?
抱歉我不会。
我也没想出来好方法。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 200100
#define eps 1e-6
using namespace std;
typedef long long ll;
int n,m;
int head[N],cnt;
struct Line
{
int u,v;
ll val;
}l[N];
struct node
{
int from,to,next;
ll val;
}edge[N<<1];
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
int ancestor[N];
int find(int x)
{
if(x==ancestor[x])return x;
return ancestor[x]=find(ancestor[x]);
}
void edgeadd(int from,int to,ll val)
{
edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
edge[cnt].next=head[from];head[from]=cnt++;
}
int deep[N],fa[N][21];
ll col[N];
void dfs(int now,int ff)
{
deep[now]=deep[ff]+1;
fa[now][0]=ff;
for(int i=head[now];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(to==ff)continue;
dfs(to,now);
col[to]=edge[i].val;
if(edge[i].val==1)
{
int fx=find(to),fy=find(now);
ancestor[fx]=fy;
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(deep[fa[x][i]]>=deep[y])
x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(deep[fa[x][i]]==deep[fa[y][i]]&&fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
ll calc(int u,int v,int Lca,ll val)
{
int ccnt=0;
while(deep[u]>deep[Lca])
{
int anc=find(u);
if(deep[anc]<=deep[Lca])break;
val/=col[anc];
ccnt++;
if(ccnt>64)return 0;
if(val==0)return 0;
u=fa[anc][0];
}
while(deep[v]>deep[Lca])
{
int anc=find(v);
if(deep[anc]<=deep[Lca])break;
val/=col[anc];
if(ccnt>64)return 0;
if(val==0)return 0;
v=fa[anc][0];
}
return val;
}
void change(int no,ll val)
{
int x=l[no].u,y=l[no].v;
if(fa[y][0]==x)swap(x,y);
col[x]=val;
if(val==1)
{
int fx=find(x),fy=find(y);
ancestor[fx]=fy;
}
}
int main()
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)ancestor[i]=i;
for(int i=1;i<n;i++)
{
scanf("%d%d%I64d",&l[i].u,&l[i].v,&l[i].val);
edgeadd(l[i].u,l[i].v,l[i].val);
edgeadd(l[i].v,l[i].u,l[i].val);
}
dfs(1,0);
for(int i=1;i<=20;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
for(int i=1;i<=m;i++)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int u,v;
ll val;
scanf("%d%d%I64d",&u,&v,&val);
int tmp=lca(u,v);
printf("%I64d\n",calc(u,v,tmp,val));
}else
{
int x;
ll val;
scanf("%d%I64d",&x,&val);
change(x,val);
}
}
}