日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

轻重链剖分

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 轻重链剖分 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

重鏈剖分

P3384 【模板】輕重鏈剖分/樹鏈剖分 $ / $ 模板代碼:

注意:

  • 如果有 \(0\) 號節點,并默認重兒子是零號節點,復雜度會退化為 \(O(n^2)\) 。原因:

    • 代碼第一次遍歷默認重兒子是0,所以無法保證每次找到重兒子。如果重兒子的節點數小于根節點,那么重兒子不會被記錄。

    • 而在第二次遍歷中,因為應該被找到的重兒子沒被找到,所以少了重邊。

    • 由于少了很多重鏈,本來可以一次跳到重鏈頂的轉移必須沿著輕鏈條很多次,時間復雜度就上去了,由 \(O(n \log n)\) 退化為 \(O(n^2)\)

      • 解決方法:將每一個節點編號都加一 。
#include<bits/stdc++.h> using namespace std; #define Maxn 100005 typedef long long ll; inline int rd() {int x=0;char ch,t=0;while(!isdigit(ch = getchar())) t|=ch=='-';while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();return x=t?-x:x; } int n,m,root,mod,tot=1,N; int val[Maxn],fa[Maxn],siz[Maxn],Bigson[Maxn]; int tp[Maxn],dep[Maxn],dfnl[Maxn],dfnr[Maxn],reg[Maxn]; // reg !!dfn是線段樹上的節點號,與所對應的真實節點號不同 int hea[Maxn],ver[Maxn*2],nex[Maxn*2]; struct TREE { int sum,laz; }tree[Maxn<<2]; void add_edge(int x,int y) { ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot; } void dfs1(int x) {siz[x]=1;for(int i=hea[x];i;i=nex[i]){if(ver[i]==fa[x]) continue;dep[ver[i]]=dep[x]+1,fa[ver[i]]=x;dfs1(ver[i]);siz[x]+=siz[ver[i]];if(siz[ver[i]]>siz[Bigson[x]]) Bigson[x]=ver[i];} } void dfs2(int x,int T) {tp[x]=T,dfnl[x]=++N,reg[N]=x;if(Bigson[x]) dfs2(Bigson[x],T);for(int i=hea[x];i;i=nex[i]){if(ver[i]==fa[x] || ver[i]==Bigson[x]) continue;dfs2(ver[i],ver[i]);}dfnr[x]=N; } void pushdown(int p,int nl,int nr) {if(tree[p].laz){int mid=(nl+nr)>>1;tree[p<<1].sum=(tree[p<<1].sum+tree[p].laz*(mid-nl+1))%mod;tree[p<<1|1].sum=(tree[p<<1|1].sum+tree[p].laz*(nr-mid))%mod;tree[p<<1].laz=(tree[p<<1].laz+tree[p].laz)%mod;tree[p<<1|1].laz=(tree[p<<1|1].laz+tree[p].laz)%mod;tree[p].laz=0;} } void build(int p,int nl,int nr) {if(nl==nr) { tree[p].sum=val[reg[nl]]; return; }int mid=(nl+nr)>>1;build(p<<1,nl,mid),build(p<<1|1,mid+1,nr);tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod; } void add(int p,int nl,int nr,int l,int r,int k) {if(nl>=l && nr<=r){tree[p].sum=(tree[p].sum+k*(nr-nl+1))%mod;tree[p].laz+=k;return;}pushdown(p,nl,nr);int mid=(nl+nr)>>1;if(mid>=l) add(p<<1,nl,mid,l,r,k);if(mid<r) add(p<<1|1,mid+1,nr,l,r,k);tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod; } int query(int p,int nl,int nr,int l,int r) {if(nl>=l && nr<=r) return tree[p].sum;pushdown(p,nl,nr);int mid=(nl+nr)>>1,ret=0;if(mid>=l) ret=query(p<<1,nl,mid,l,r);if(mid<r) ret+=query(p<<1|1,mid+1,nr,l,r);tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;return ret%mod; } void add_path(int x,int y,int k) // 注意:這道題的權重在 點 上 {while(tp[x]!=tp[y]){if(dep[tp[x]]<dep[tp[y]]) swap(x,y);add(1,1,n,dfnl[tp[x]],dfnl[x],k);x=fa[tp[x]];}if(dep[x]<dep[y]) swap(x,y);add(1,1,n,dfnl[y],dfnl[x],k); } int query_path(int x,int y) {int ret=0;while(tp[x]!=tp[y]){if(dep[tp[x]]<dep[tp[y]]) swap(x,y);ret=(ret+query(1,1,n,dfnl[tp[x]],dfnl[x]))%mod;x=fa[tp[x]];}if(dep[x]<dep[y]) swap(x,y);ret=(ret+query(1,1,n,dfnl[y],dfnl[x]))%mod;return ret; } int main() {//freopen(".in","r",stdin);//freopen(".out","w",stdout);n=rd(),m=rd(),root=rd(),mod=rd();for(int i=1;i<=n;i++) val[i]=rd();for(int i=1,u,v;i<n;i++) u=rd(),v=rd(),add_edge(u,v),add_edge(v,u);dfs1(root),dfs2(root,root),build(1,1,n);for(int i=1,opt,x,y,z;i<=m;i++){opt=rd();if(opt==1) x=rd(),y=rd(),z=rd()%mod,add_path(x,y,z);else if(opt==2) x=rd(),y=rd(),printf("%d\n",query_path(x,y));else if(opt==3) x=rd(),z=rd(),add(1,1,n,dfnl[x],dfnr[x],z);else x=rd(),printf("%d\n",query(1,1,n,dfnl[x],dfnr[x]));}//fclose(stdin);//fclose(stdout);return 0; }

總結

以上是生活随笔為你收集整理的轻重链剖分的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。