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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

洛谷3384(树链剖分模板题)

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

題目描述
如題,已知一棵包含N個結點的樹(連通且無環),每個節點上包含一個數值,需要支持以下操作:

操作1: 格式: 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z

操作2: 格式: 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和

操作3: 格式: 3 x z 表示將以x為根節點的子樹內所有節點值都加上z

操作4: 格式: 4 x 表示求以x為根節點的子樹內所有節點值之和

輸入輸出格式
輸入格式:
第一行包含4個正整數N、M、R、P,分別表示樹的結點個數、操作個數、根節點序號和取模數(即所有的輸出結果均對此取模)。

接下來一行包含N個非負整數,分別依次表示各個節點上初始的數值。

接下來N-1行每行包含兩個整數x、y,表示點x和點y之間連有一條邊(保證無環且連通)

接下來M行每行包含若干個正整數,每行表示一個操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

輸出格式:
輸出包含若干行,分別依次表示每個操作2或操作4所得的結果(對P取模)

輸入輸出樣例
輸入樣例#1:
5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
輸出樣例#1:
2
21
說明
時空限制:1s,128M

數據規模:

對于30%的數據: N \leq 10, M \leq 10 N≤10,M≤10
對于70%的數據: N \leq {10}^3, M \leq {10}^3 N≤10
3
,M≤10
3

對于100%的數據: N \leq {10}^5, M \leq {10}^5 N≤10
5
,M≤10
5

( 其實,純隨機生成的樹LCA+暴力是能過的,可是,你覺得可能是純隨機的么233 )

樣例說明:

樹的結構如下:

各個操作如下:

故輸出應依次為2、21(重要的事情說三遍:記得取模)
搞了一下午的樹鏈剖分,可算是寫出來個東西。學習樹鏈剖分應該先掌握線段樹,dfs序。否則學起來會很困難。
代碼總之很長,而且之前都是分開寫線段樹,dfs之類的,這一次綜合起來還是有點困難的。
代碼如下:

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<queue> #define ll long long using namespace std;const int maxx=1e5+100; int fa[maxx],son[maxx],dep[maxx]; int pre[maxx],id[maxx],top[maxx]; int size[maxx],a[maxx],head[maxx]; int n,m,root,mod,sign; int tot; struct edge{int to;int next; }e[maxx*2]; struct node{int l;int r;int v;int lazy; }p[maxx*4]; /*-----------事前準備---------*/ int inn() { char ch; int a=0; while((ch=getchar())==' '||ch=='\n'); a+=ch-'0'; while((ch=getchar())!=' '&&ch!='\n') { a*=10; a+=ch-'0'; } return a; } void init() {tot=0;sign=0;memset(dep,0,sizeof(dep));memset(size,0,sizeof(size));memset(head,0,sizeof(head)); } void addedge(int x,int y) {e[++tot].next=head[x];e[tot].to=y;head[x]=tot; } /*----------------dfs---------------*/ void dfs1(int u,int f) {size[u]=1;dep[u]=dep[fa[u]]+1;for(int i=head[u];i;i=e[i].next){int to=e[i].to;if(to==f) continue;//dep[to]=dep[u]+1;fa[to]=u;dfs1(to,u);size[u]+=size[to];if(size[to]>size[son[u]]) son[u]=to;} } void dfs2(int u,int Top) {top[u]=Top;id[u]=++sign;pre[sign]=u;if(son[u]) dfs2(son[u],Top);for(int i=head[u];i;i=e[i].next){int to=e[i].to;if(to!=fa[u]&&to!=son[u])dfs2(to,to);} } /*-------------線段樹-------------*/ void pushup(int cur) {p[cur].v=(p[2*cur].v+p[2*cur+1].v)%mod; } void pushdown(int cur) {if(p[cur].lazy){p[2*cur].lazy=(p[cur].lazy+p[cur*2].lazy)%mod;p[2*cur+1].lazy=(p[cur].lazy+p[2*cur+1].lazy)%mod;p[2*cur].v=(p[2*cur].v+(p[2*cur].r-p[2*cur].l+1)*p[cur].lazy)%mod;p[2*cur+1].v=(p[2*cur+1].v+(p[2*cur+1].r-p[2*cur+1].l+1)*p[cur].lazy)%mod;p[cur].lazy=0;} } void build(int l,int r,int cur) {p[cur].l=l;p[cur].r=r;p[cur].lazy=0;if(l==r){p[cur].v=a[pre[l]];return;}int mid=(l+r)/2;build(l,mid,2*cur);build(mid+1,r,2*cur+1);pushup(cur); } void update(int l,int r,int cur,int add) {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){p[cur].v=(p[cur].v+(p[cur].r-p[cur].l+1)*add%mod)%mod;p[cur].lazy=(p[cur].lazy+add)%mod;return ;}pushdown(cur);int mid=(L+R)/2;if(r<=mid) update(l,r,2*cur,add);else if(l>mid) update(l,r,2*cur+1,add);else {update(l,mid,2*cur,add);update(mid+1,r,2*cur+1,add);}pushup(cur); } int query(int l,int r,int cur) {int L=p[cur].l;int R=p[cur].r;if(l<=L&&R<=r){return p[cur].v%mod;}pushdown(cur);int mid=(L+R)/2;if(r<=mid) return query(l,r,2*cur)%mod;else if(l>mid) return query(l,r,2*cur+1)%mod;else return (query(l,mid,2*cur)+query(mid+1,r,2*cur+1))%mod; } /*--------------樹鏈剖分-------------*/ int Query(int x,int y) {int ret=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);(ret+=query(id[top[x]],id[x],1))%=mod;x=fa[top[x]];}if(id[x]>id[y]) swap(x,y);return (ret+query(id[x],id[y],1))%mod; } void Update(int x,int y,int z) {while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);update(id[top[x]],id[x],1,z);x=fa[top[x]];}if(id[x]>id[y]) swap(x,y);update(id[x],id[y],1,z); } /*-----------主函數-----------*/ int main() {while(scanf("%d%d%d%d",&n,&m,&root,&mod)!=EOF){init(); for(int i=1;i<=n;i++) a[i]=inn();int x,y;for(int i=1;i<n;i++){x=inn();y=inn();addedge(x,y);addedge(y,x);}dep[root]=1;dfs1(root,0);dfs2(root,root);build(1,n,1);int k,z;while(m--){k=inn();if(k==1){x=inn();y=inn();z=inn();Update(x,y,z);}else if(k==2){x=inn();y=inn();printf("%d\n",Query(x,y));}else if(k==3){x=inn();y=inn();update(id[x],id[x]+size[x]-1,1,y);}else if(k==4){x=inn();printf("%d\n",query(id[x],id[x]+size[x]-1,1));}}return 0;} }

數據結構一般代碼量很多,所以一定不能心浮氣躁。而且要多敲,這樣才能少出錯誤
努力加油a啊,(o)/~

總結

以上是生活随笔為你收集整理的洛谷3384(树链剖分模板题)的全部內容,希望文章能夠幫你解決所遇到的問題。

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