题意:给你一棵树,每条边上有权值。有两个操作
1. u v p 从u~v的路径上用p除每跳边的权值,向下取整
2. u p 将第u条边的权值改为p
思路:树链剖分 呃…算是模板题吧 因为这道题学了十几个小时的树链剖分
照着卿神的blog理解的Orz 卿神blog
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define sfor(i,a,h) for(i=h[a];i!=-1;i=e[i].next)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
#define cheak(i) printf("%d ",i)
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define inf 0x3f3f3f3f
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 200005
#define maxm maxn*maxn
#define lson(x) (splay[x].son[0])
#define rson(x) (splay[x].son[1])
const long long kkk=1e18+10;
struct node
{
int next,sta,to;
LL val;
}e[maxn*2],tmp[maxn];
int tot,tim,h[maxn],n,m;
int fa[maxn],son[maxn];
int top[maxn],siz[maxn],Rank[maxn];
int dep[maxn],tid[maxn];
LL A[maxn];
void add_edge(int a,int b,int c)
{
e[++tot].next=h[a];
e[tot].sta=a;
e[tot].to=b;
e[tot].val=c;
h[a]=tot;
}
void start()
{
mem(h,-1);mem(son,-1);
tot=0,tim=0;
}
//树链剖分
void dfs1(int u,int father,int d)
{
//printf("**%d %d %d\n",u,father,d);
fa[u]=father;
dep[u]=d;
siz[u]=1;
for(int i=h[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v!=father)
{
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[u]==-1||siz[v]>siz[son[u]])
son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
//printf("++%d %d\n",u,tp);
tid[u]=++tim;
Rank[tim]=u;
top[u]=tp;
if(son[u]==-1) return ;
dfs2(son[u],tp);
for(int i=h[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[u]&&v!=son[u])
dfs2(v,v);
}
}
//线段树
struct Segment
{
LL val,lazy;
}tree[maxn*4];
void Push_up(int index)
{
if(tree[index*2].val==0) tree[index].val=1;
if(tree[index*2+1].val==0) tree[index].val=1;
double x1=tree[index*2].val;
double x2=tree[index*2+1].val;
if(log(x1)+log(x2)>log(kkk*1.0))
tree[index].val=kkk+5;
else
tree[index].val=tree[index*2].val*tree[index*2+1].val;
}
void build(int l,int r,int index)
{
tree[index].val=1;
if(l==r)
{
tree[index].val=A[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,index*2);
build(mid+1,r,index*2+1);
Push_up(index);
}
void update(int l,int r,int x,LL val,int index)
{
if(l==r)
{
tree[index].val=val;
return ;
}
int mid=(l+r)/2;
if(x<=mid) update(l,mid,x,val,index*2);
else update(mid+1,r,x,val,index*2+1);
Push_up(index);
}
LL query(int l,int r,int L,int R,int index)
{
//printf("****%d %d %d %d %d\n",l,r,L,R,index);
if(L<=l&&r<=R) return tree[index].val;
int mid=(l+r)/2;
LL ans=1;
if(L<=mid)
{
LL x=query(l,mid,L,R,index*2);
//printf("@@@%lld\n",x);
if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))//判断是否大于1e18 如果大于直接等于1e18+正整数 因为答案肯定是0
ans=kkk+203;
else ans*=x;
}
if(R>mid)
{
LL x=query(mid+1,r,L,R,index*2+1);
//printf("@@%lld\n",x);
if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
ans=kkk+203;
else ans*=x;
}
return ans;
}
LL solve1(int u,int v)
{
LL ans=1;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
//printf("**%d %d\n",tid[top[u]],tid[u]);
LL x=query(2,n,tid[top[u]],tid[u],1);
//printf("+++%lld\n",x);
if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
ans=kkk+203;
else ans*=x;
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
if(u!=v)
{
//printf("%d %d\n",tid[u]+1,tid[v]);
LL x=query(2,n,tid[u]+1,tid[v],1);
//printf("++++%lld\n",x);
if(log(ans*1.0)+log(x*1.0)>log(kkk*1.0))
ans=kkk+203;
else ans*=x;
}
return ans;
}
void solve2(int i,LL val)
{
if(dep[tmp[i].sta]>dep[tmp[i].to])
update(2,n,tid[tmp[i].sta],val,1);
else update(2,n,tid[tmp[i].to],val,1);
}
int main()
{
int k,i,u,v,oper;
LL x;
start();
scanf("%d%d",&n,&k);
rfor(i,1,n-1)
{
scanf("%d%d%lld",&u,&v,&x);
tmp[i].sta=u,tmp[i].to=v,tmp[i].val=x;
add_edge(u,v,x);add_edge(v,u,x);
}
dfs1(1,0,0);
dfs2(1,1);
rfor(i,1,n-1)
{
if(dep[tmp[i].sta]>dep[tmp[i].to])
A[tid[tmp[i].sta]]=tmp[i].val;
else A[tid[tmp[i].to]]=tmp[i].val;
}
build(2,n,1);
while(k--)
{
scanf("%d",&oper);
if(oper==1)
{
scanf("%d%d%lld",&u,&v,&x);
printf("%lld\n",x/solve1(u,v));
}
else
{
scanf("%d%lld",&i,&x);
solve2(i,x);
}
}
return 0;
}