CF593D Happy Tree Party 题解
CF593D Happy Tree Party 题解
CF593D Happy Tree Party
题意
给一棵 个节点的树,有 个操作,一共有两种操作:
-
表示在 到 的路径上,每次让 ,其中 表示边权,询问最后 的值。
-
表示把第 条边的权值改为 。
分析
显然能看出可以用树剖。容易想到,操作一可以用线段树维护,让 除以区间里的每一个数即可。操作二就相当于一个单点修改。但是操作的都是边权,因此可以把边权都向下推到点权上,如图。
然后重链剖分一下,query 的时候每次把重链顶深度更大的向上跳到重链顶,让 除以链上的每一个点。最后在处理一下剩余部分即可。同时还要注意一些细节,因为 long long 乘 long long 可能会炸,因此开 long double,另外除的时候判一下除数为0的情况,不然可能会 RE。
代码
#include <bits/stdc++.h>
#define int long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long double ll;
typedef unsigned long long ull;
typedef pair<int,int> Pair;
const int inf=2139062143;
inline void qread(){}template<class T1,class ...T2>
inline void qread(T1 &a,T2&... b)
{
register T1 x=0;register bool f=false;char ch=getchar();
while(ch<'0') f|=(ch=='-'),ch=getchar();
while(ch>='0') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x=(f?-x:x);a=x;qread(b...);
}
template<class T> T qmax(T x,T y){return x>y?x:y;}
template<class T,class ...Arg> T qmax(T x,T y,Arg ...arg){return qmax(x>y?x:y,arg...);}
template<class T> T qmin(T x,T y){return x<y?x:y;}
template<class T,class ...Arg> T qmin(T x,T y,Arg ...arg){return qmin(x<y?x:y,arg...);}
const int MAXN=2e5+7;
int n,m,hson[MAXN],fa[MAXN],cnt[MAXN],dep[MAXN],top[MAXN],id[MAXN],tot,a[MAXN],val[MAXN];
vector<Pair>Tree[MAXN];int c;
namespace Seg_tree
{
const int MX=8000007;
ll tree[MX];
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;}
inline void push_up(int p){tree[p]=tree[ls(p)]*tree[rs(p)];}
void build(int a[],int p,int l,int r)
{
if(l==r) tree[p]=(long double)(a[l]);
else
{
int mid=(l+r)>>1;
build(a,ls(p),l,mid);
build(a,rs(p),mid+1,r);
push_up(p);
}
}
void update(int p,int l,int r,int pos,ll k)
{
if(l==r) tree[p]=k;
else
{
int mid=(l+r)>>1;
if(mid>=pos) update(ls(p),l,mid,pos,k);
else update(rs(p),mid+1,r,pos,k);
push_up(p);
}
}
void query(int p,int l,int r,int L,int R)
{
if(!c) return; // 如果c已经是0了,再怎么除还是0
if(L<=l&&r<=R)
{
if(!tree[p]) c=0; // 特判除数为0的情况
else c/=tree[p];
}
else
{
int mid=(l+r)>>1;
if(L<=mid) query(ls(p),l,mid,L,R);
if(R>mid) query(rs(p),mid+1,r,L,R);
}
}
}
using namespace Seg_tree;
void dfs(int u,int f)
{
cnt[u]=1;
for(auto son:Tree[u])
{
if(son.first==f) continue;
dep[son.first]=dep[u]+1;fa[son.first]=u;
dfs(son.first,u);cnt[u]+=cnt[son.first];
if(cnt[son.first]>cnt[hson[u]]) hson[u]=son.first;
}
}
void dfs1(int u,int f,int t)
{
id[u]=++tot;a[tot]=val[u];top[u]=t;
if(hson[u]) dfs1(hson[u],u,t);
for(auto son:Tree[u]) if(son.first!=hson[u]&&son.first!=f) dfs1(son.first,u,son.first);
}
void query_chain(int x,int y)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); // 跳重链顶更深的
if(!c) return;
query(1,1,n,id[fx],id[x]);
x=fa[fx],fx=top[x];
}
if(!c) return;
if(id[x]>id[y]) swap(x,y);
query(1,1,n,id[x]+1,id[y]);
}
map<int,Pair>mp;
signed main()
{
qread(n,m);int i,j;
for(i=0;i<n-1;i++)
{
int u,v,w;qread(u,v,w);
Tree[u].push_back(Pair(v,w));
Tree[v].push_back(Pair(u,w));
mp[i]=Pair(u,v);
}fa[1]=1;dep[1]=0;dfs(1,0);
for(i=1;i<=n;i++)
{
for(auto j:Tree[i])
{
int u=i,v=j.first;
if(dep[u]>dep[v]) swap(u,v); // 这条边推到了深度更深的点上
val[v]=j.second;
}
}
dfs1(1,0,1);build(a,1,1,n);int num=0;
for(i=0;i<m;i++)
{
int op,x,y;qread(op);
if(op==1)
{
qread(x,y,c);
query_chain(x,y);
printf("%lld\n",c);
}
if(op==2)
{
qread(x,c);
int u=mp[x-1].first,v=mp[x-1].second;
if(id[u]>id[v]) swap(u,v);
update(1,1,n,id[v],c); // 单点修改
}
}
return 0;
}
本文作者:l_x_y
本文链接:https://www.cnblogs.com/lxy-2022/p/CF593D-Solution.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
标签:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步