樹鏈剖分模板
阿新 • • 發佈:2017-06-12
amp pan mes bsp -m 依次 代碼 clu tree
P3384 【模板】樹鏈剖分
題目描述
如題,已知一棵包含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<=10,M<=10
對於70%的數據:N<=1000,M<=1000
對於100%的數據:N<=100000,M<=100000
(其實,純隨機生成的樹LCA+暴力是能過的,可是,你覺得可能是純隨機的麽233)
樣例說明:
樹的結構如下:
各個操作如下:
故輸出應依次為2、21(重要的事情說三遍:記得取模)
半夜不適合敲代碼,尤其這種結構體數組中多個定義的……
碼程四十分鐘,調程三小時……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5using namespace std; 6 int n,m,r,p,cnt,tot; 7 int val[100010],head[100010]; 8 struct data{ 9 int next,to; 10 }edge[200010]; 11 struct dt{ 12 int fa,son,size,deep,top,num,end; 13 //son 重兒子 14 //size 子結點個數 15 //top 當前結點所在鏈的頂結點 16 }tree[100010]; 17 struct tr{ 18 int sum,mark; 19 }segtree[400010]; 20 void add_edge(int start,int ed){ 21 edge[++cnt].next=head[start]; 22 edge[cnt].to=ed; 23 head[start]=cnt; 24 return; 25 } 26 void dfs_weight(int u){ 27 tree[u].size=1; 28 tree[u].son=0; 29 for(int i=head[u];i;i=edge[i].next) 30 if(edge[i].to!=tree[u].fa){ 31 tree[edge[i].to].fa=u; 32 tree[edge[i].to].deep=tree[u].deep+1; 33 dfs_weight(edge[i].to); 34 tree[u].size+=tree[edge[i].to].size; 35 if(tree[edge[i].to].size>tree[tree[u].son].size) tree[u].son=edge[i].to; 36 } 37 return; 38 } 39 void dfs_build(int u,int tp){ 40 tree[u].top=tp; 41 tree[u].num=++tot; 42 if(tree[u].son){ 43 dfs_build(tree[u].son,tp); 44 for(int i=head[u];i;i=edge[i].next) 45 if(edge[i].to!=tree[u].fa&&edge[i].to!=tree[u].son) dfs_build(edge[i].to,edge[i].to); 46 } 47 tree[u].end=tot; 48 return; 49 } 50 void down(int pos,int ll,int mid,int rr){ 51 if(segtree[pos].mark){ 52 segtree[pos<<1].mark+=segtree[pos].mark; 53 segtree[pos<<1|1].mark+=segtree[pos].mark; 54 segtree[pos<<1].sum+=(mid-ll+1)*segtree[pos].mark; 55 segtree[pos<<1].sum%=p; 56 segtree[pos<<1|1].sum+=(rr-mid)*segtree[pos].mark; 57 segtree[pos<<1|1].sum%=p; 58 segtree[pos].mark=0; 59 return; 60 } 61 } 62 void update(int pl,int pr,int vl,int pos,int ll,int rr){ 63 if(pl<=ll&&pr>=rr){ 64 segtree[pos].mark+=vl; 65 segtree[pos].sum+=(rr-ll+1)*vl; 66 segtree[pos].sum%=p; 67 return; 68 } 69 int mid=(ll+rr)>>1; 70 down(pos,ll,mid,rr); 71 if(pl<=mid) update(pl,pr,vl,pos<<1,ll,mid); 72 if(pr>mid) update(pl,pr,vl,pos<<1|1,mid+1,rr); 73 segtree[pos].sum=segtree[pos<<1].sum+segtree[pos<<1|1].sum; 74 segtree[pos].sum%=p; 75 return; 76 } 77 void add_val(int aa,int bb,int vl){ 78 int f1=tree[aa].top,f2=tree[bb].top; 79 while(f1!=f2){ 80 if(tree[f1].deep<tree[f2].deep){ 81 update(tree[f2].num,tree[bb].num,vl,1,1,n); 82 bb=tree[f2].fa; 83 f2=tree[bb].top; 84 } 85 else{ 86 update(tree[f1].num,tree[aa].num,vl,1,1,n); 87 aa=tree[f1].fa; 88 f1=tree[aa].top; 89 } 90 } 91 if(tree[aa].deep<tree[bb].deep) update(tree[aa].num,tree[bb].num,vl,1,1,n); 92 else update(tree[bb].num,tree[aa].num,vl,1,1,n); 93 return; 94 } 95 int ask(int pl,int pr,int pos,int ll,int rr){ 96 if(pl<=ll&&pr>=rr) return segtree[pos].sum; 97 int mid=(ll+rr)>>1; 98 down(pos,ll,mid,rr); 99 int ans=0; 100 if(pl<=mid){ 101 ans+=ask(pl,pr,pos<<1,ll,mid); 102 ans%=p; 103 } 104 if(pr>mid){ 105 ans+=ask(pl,pr,pos<<1|1,mid+1,rr); 106 ans%=p; 107 } 108 return ans; 109 } 110 int ask_some(int aa,int bb){ 111 int f1=tree[aa].top,f2=tree[bb].top; 112 int ans=0; 113 while(f1!=f2){ 114 if(tree[f1].deep<tree[f2].deep){ 115 ans+=ask(tree[f2].num,tree[bb].num,1,1,n); 116 ans%=p; 117 bb=tree[f2].fa; 118 f2=tree[bb].top; 119 } 120 else{ 121 ans+=ask(tree[f1].num,tree[aa].num,1,1,n); 122 ans%=p; 123 aa=tree[f1].fa; 124 f1=tree[aa].top; 125 } 126 } 127 if(tree[aa].deep<tree[bb].deep){ 128 ans+=ask(tree[aa].num,tree[bb].num,1,1,n); 129 ans%=p; 130 } 131 else{ 132 ans+=ask(tree[bb].num,tree[aa].num,1,1,n); 133 ans%=p; 134 } 135 return ans; 136 } 137 int main(){ 138 scanf("%d%d%d%d",&n,&m,&r,&p); 139 for(int i=1;i<=n;i++) scanf("%d",&val[i]); 140 int x,y; 141 for(int i=1;i<n;i++){ 142 scanf("%d%d",&x,&y); 143 add_edge(x,y); 144 add_edge(y,x); 145 } 146 tree[r].deep=0; 147 dfs_weight(r); 148 dfs_build(r,r);; 149 for(int i=1;i<=n;i++) update(tree[i].num,tree[i].num,val[i],1,1,n); 150 int od,a,b,c; 151 for(int i=1;i<=m;i++){ 152 scanf("%d",&od); 153 if(od==1){ 154 scanf("%d%d%d",&a,&b,&c); 155 add_val(a,b,c); 156 continue; 157 } 158 if(od==2){ 159 scanf("%d%d",&a,&b); 160 printf("%d\n",ask_some(a,b)); 161 continue; 162 } 163 if(od==3){ 164 scanf("%d%d",&a,&b); 165 update(tree[a].num,tree[a].end,b,1,1,n); 166 continue; 167 } 168 if(od==4){ 169 scanf("%d",&a); 170 printf("%d\n",ask(tree[a].num,tree[a].end,1,1,n)); 171 continue; 172 } 173 } 174 return 0; 175 }
樹鏈剖分模板