CF593D Happy Tree Party 题解

CF593D Happy Tree Party 题解

CF593D Happy Tree Party

题意

给一棵 \(n\) 个节点的树,有 \(m\) 个操作,一共有两种操作:

  • \(1\ x\ y\ c\) 表示在 \(x\)\(y\) 的路径上,每次让 \(c \leftarrow \left\lfloor\dfrac{c}{w}\right\rfloor\) ,其中 \(w\) 表示边权,询问最后 \(c\) 的值。

  • \(2\ x\ c\) 表示把第 \(x\) 条边的权值改为 \(c\)

分析

显然能看出可以用树剖。容易想到,操作一可以用线段树维护,让 \(c\) 除以区间里的每一个数即可。操作二就相当于一个单点修改。但是操作的都是边权,因此可以把边权都向下推到点权上,如图。

然后重链剖分一下,query 的时候每次把重链顶深度更大的向上跳到重链顶,让 \(c\) 除以链上的每一个点。最后在处理一下剩余部分即可。同时还要注意一些细节,因为 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;
}
posted @ 2022-03-30 17:35  l_x_y  阅读(53)  评论(0编辑  收藏  举报