1. 程式人生 > 其它 >CF593D Happy Tree Party 題解

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;
}