CF593D Happy Tree Party 題解
阿新 • • 發佈:2022-03-30
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; }