luogu P3384 【模板】树链剖分
Time Limit: 1 Sec
Memory Limit: 128 MBDescription
如题,已知一棵包含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为根节点的子树内所有节点值之和
Input
第一行包含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
Output
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
Sample Input
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
Sample Output
2
21
HINT
说明
时空限制:1s,128M
数据规模:
对于30%的数据:\(N \leq 10, M \leq 10\)
对于70%的数据: \(N \leq {10}^3, M \leq {10}^3\)
对于100%的数据: \(N \leq {10}^5, M \leq {10}^5\)
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
题目地址: luogu P3384 【模板】树链剖分
题目大意: 已经很简洁了
题解:
树剖模板写半天
ghydalao天下第一
AC代码
#include <stdio.h>
#include <algorithm>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,Q,rt,Mod;
int a[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct edge{
int to,next;
}e[N+N];
int cnt_edge,last[N];
inline void add_edge(int u,int v){
e[++cnt_edge]=(edge){v,last[u]};last[u]=cnt_edge;
}
int fa[N],sz[N],dep[N],son[N];
void dfs1(int u,int father){
fa[u]=father;sz[u]=1;
dep[u]=dep[father]+1;
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==father)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v])
son[u]=v;
}
}
int Knum,top[N],pos[N],sop[N],End[N];
void dfs2(int u,int chain){
top[u]=chain;
pos[u]=++Knum;
sop[Knum]=u;
if(!son[u]){
End[u]=Knum;
return;
}
dfs2(son[u],chain);
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v!=fa[u] && v!=son[u])
dfs2(v,v);
}
End[u]=Knum;
}
inline int mo(int x){
return (x>=Mod) ? x-Mod : x;
}
int sum[N<<2],tag[N<<2];
inline void pushdown(int k,int l,int r,int mid){
if(!tag[k])return;
sum[k<<1]=mo(sum[k<<1]+(ll)(mid-l+1)*tag[k]%Mod);
sum[k<<1|1]=mo(sum[k<<1|1]+(ll)(r-mid)*tag[k]%Mod);
tag[k<<1]=mo(tag[k<<1]+tag[k]);
tag[k<<1|1]=mo(tag[k<<1|1]+tag[k]);
tag[k]=0;
}
inline void pushup(int k){
sum[k]=mo(sum[k<<1]+sum[k<<1|1]);
}
void build(int k,int l,int r){
if(l==r){
sum[k]=a[sop[l]];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void change(int k,int l,int r,int L,int R,int val){
if(l==L && R==r){
sum[k]=mo(sum[k]+(ll)(r-l+1)*val%Mod);
tag[k]=mo(tag[k]+val);
return;
}
int mid=(l+r)>>1;
pushdown(k,l,r,mid);
if(R<=mid)change(k<<1,l,mid,L,R,val);
else if(L>mid)change(k<<1|1,mid+1,r,L,R,val);
else change(k<<1,l,mid,L,mid,val),change(k<<1|1,mid+1,r,mid+1,R,val);
pushup(k);
}
int query(int k,int l,int r,int L,int R){
if(l==L && R==r)return sum[k];
int mid=(l+r)>>1;
pushdown(k,l,r,mid);
if(R<=mid)return query(k<<1,l,mid,L,R);
else if(L>mid)return query(k<<1|1,mid+1,r,L,R);
else return mo(query(k<<1,l,mid,L,mid)+query(k<<1|1,mid+1,r,mid+1,R));
}
void update_path(int a,int b,int val){
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])swap(a,b);
change(1,1,n,pos[top[a]],pos[a],val);
a=fa[top[a]];
}
if(dep[a]<dep[b])swap(a,b);
change(1,1,n,pos[b],pos[a],val);
}
int query_path(int a,int b){
int res=0;
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]])swap(a,b);
res=mo(res+query(1,1,n,pos[top[a]],pos[a]));
a=fa[top[a]];
}
if(dep[a]<dep[b])swap(a,b);
res=mo(res+query(1,1,n,pos[b],pos[a]));
return res;
}
inline void update_subtree(int x,int val){
change(1,1,n,pos[x],End[x],val);
}
inline int query_subtree(int x){
return query(1,1,n,pos[x],End[x]);
}
int main(){
n=read(),Q=read(),rt=read(),Mod=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
dfs1(rt,0);
dfs2(rt,rt);
build(1,1,n);
while(Q--){
int cas=read();
if(cas==1){
int x=read(),y=read(),val=read();
update_path(x,y,val);
}else if(cas==2){
int x=read(),y=read();
printf("%d\n",query_path(x,y));
}else if(cas==3){
int x=read(),val=read();
update_subtree(x,val);
}else{
int x=read();
printf("%d\n",query_subtree(x));
}
}
return 0;
}
作者:skl_win
出处:https://www.cnblogs.com/shaokele/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。