【洛谷P3384】【模板】树链剖分板子 hdu 3966

贴一个觉得写的不错的链接:https://www.cnblogs.com/ivanovcraft/p/9019090.html

 

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=100010;
typedef long long ll;
using namespace std;
struct edge{
	int v,nex;
}e[maxn<<1];


int fa[maxn],dep[maxn],fp[maxn],top[maxn],son[maxn],sz[maxn];
int head[maxn],tot,n,m,a[maxn],mod,root,p[maxn],cnt;
ll sum[maxn<<2],laz[maxn<<2];

int read(){
    int ans=0; char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
void add(int u,int v) {
    e[tot].v=v; e[tot].nex=head[u];
    head[u]=tot++;
}
void dfs1(int u) {
    sz[u]=1,son[u]=0;
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=fa[u]) {
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs1(v);
            if(sz[v]>sz[son[u]])son[u]=v;
            sz[u]+=sz[v];
        }
    }
}

void dfs2(int u,int tp) {
    p[u]=++cnt;
    fp[p[u]]=u;
    top[u]=tp;
    if(son[u])dfs2(son[u],tp);
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=son[u]&&v!=fa[u])dfs2(v,v);
    }
}
void deal(int l,int r,int rt,ll v){
    laz[rt]+=v,sum[rt]+=(ll)(r-l+1)*v;
}
void push_up(int rt){
    sum[rt]=sum[lson]+sum[rson];
}
void build(int l,int r,int rt){
	if (l==r){
		sum[rt]=a[fp[l]];
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,lson);
	build(mid+1,r,rson);
	push_up(rt);
}

void push_down(int l,int r,int rt){
    if(laz[rt]){
        int mid=(l+r)/2;
        deal(l,mid,lson,laz[rt]);
        deal(mid+1,r,rson,laz[rt]);
        laz[rt]=0;
    }
}

void update(int ql,int qr,int l,int r,int rt,ll v){
	if (l>=ql&&r<=qr){
        deal(l,r,rt,v);
		return;
	}
	push_down(l,r,rt);
	int mid=(l+r)/2;
	if(mid>=ql) update(ql,qr,l,mid,lson,v);
    if(mid<qr) update(ql,qr,mid+1,r,rson,v);
	push_up(rt);
}

void change(int x,int y,ll v){
	int fx=top[x],fy=top[y];
	while (fx!=fy){
		if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
		update(p[fx],p[x],1,n,1,v);
		x=fa[fx],fx=top[x];
	}
	if (dep[x]>dep[y]) swap(x,y);
	update(p[x],p[y],1,n,1,v);
}

ll query(int ql,int qr,int l,int r,int rt){
	if (l>=ql&&r<=qr) {
        return sum[rt];
	}
	push_down(l,r,rt);
	ll now=0;
    int mid=(l+r)/2;
	if(mid>=ql) now=(now+query(ql,qr,l,mid,lson))%mod;
    if(mid<qr) now=(now+query(ql,qr,mid+1,r,rson))%mod;
	return now;
}

ll fin(int x,int y){
	ll now=0;
	int fx=top[x],fy=top[y];
	while (fx!=fy){
		if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
		now+=query(p[fx],p[x],1,n,1),now%=mod;
		x=fa[fx],fx=top[x];
	}
	if (dep[x]>dep[y]) swap(x,y);
	now=(now+query(p[x],p[y],1,n,1))%mod;
	return now;
}

int main(){
    int x,y,op;
    memset(head,-1,sizeof(head));
	n=read(),m=read(),root=read(),mod=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n-1) x=read(),y=read(),add(x,y),add(y,x);
	dfs1(root);
	dfs2(root,root);
	build(1,n,1);
	ll w;
	while (m--){
		op=read(),x=read();
		if(op==1){
            y=read();
            scanf("%lld",&w);
            change(x,y,w);
		}
		else if(op==2){
            y=read();
            printf("%lld\n",fin(x,y));
		}
		else if(op==3){
            scanf("%lld",&w);
            update(p[x],p[x]+sz[x]-1,1,n,1,w);
		}
		else{
            printf("%lld\n",(query(p[x],p[x]+sz[x]-1,1,n,1))%mod);
		}
	}
	return 0;
}

 

 

终于把这个坑填上了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50010;
struct edge {
    int v,nex;
} e[maxn<<1];
int head[maxn],tot;
int dep[maxn],p[maxn],fp[maxn],fa[maxn],top[maxn],son[maxn],siz[maxn];
//p为dfs序,top为当前节点的重链顶端,fp是当前结点在树状数组中的位置
int cnt;
int num[maxn];
void Add(int u,int v) {
    e[tot].v=v;
    e[tot].nex=head[u];
    head[u]=tot++;
}
void dfs(int u) {
    siz[u]=1,son[u]=0;
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=fa[u]) {
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs(v);
            if(siz[v]>siz[son[u]])son[u]=v;
            siz[u]+=siz[v];
        }
    }
}
void build(int u,int tp) {
    p[u]=++cnt;
    fp[p[u]]=u;
    top[u]=tp;
    if(son[u])build(son[u],tp);
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=son[u]&&v!=fa[u])build(v,v);
    }
}
//树状数组
int arr[maxn];
inline int lowbit(int x){return x&(-x);}
inline int query(int x) {
    int res=0;
    while(x)res+=arr[x],x-=lowbit(x);
    return res;
}
inline void add(int x,int n) {
    while(x<maxn)arr[x]+=n,x+=lowbit(x);
}
inline int update(int x,int y,int n) {
    add(x,n);
    add(y+1,-n);
}
void change(int a,int b,int x) {
    int f1=top[a],f2=top[b],tmp=0;
    while(f1!=f2) {
        if(dep[f1]<dep[f2])swap(f1,f2),swap(a,b);
        update(p[f1],p[a],x);
        a=fa[f1],f1=top[a];
    }
    // if(a==b)return;
    if(dep[a]>dep[b])swap(a,b);
    update(p[a],p[b],x);
}

int n,m,q,a,b,c;
char op[10];
int main() {
    int T;
    //freopen("f.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&m,&q)) {
        memset(head,-1,sizeof(head));
        memset(arr,0,sizeof(arr));
        cnt=tot=0;
        for(int i=1; i<=n; i++)scanf("%d",&num[i]);
        for(int i=0; i<m; i++) {
            scanf("%d%d",&a,&b);
            Add(a,b);
            Add(b,a);
        }
        dfs(1);
        build(1,1);
        for(int i=1;i<=n;i++)update(p[i],p[i],num[i]);
        while(q--) {
            scanf("%s",op);
            if(op[0]=='Q') {
                scanf("%d",&a);
                printf("%d\n",query(p[a]));
            } else {
                scanf("%d%d%d",&a,&b,&c);
                if(op[0]=='D')c=-c;
                change(a,b,c);
            }
        }
    }
    return 0;
}

以下板子

题目描述

如题,已知一棵包含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为根节点的子树内所有节点值之和

 

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=100010;
typedef long long ll;
using namespace std;
struct edge{
	int v,nex;
}e[maxn<<1];


int fa[maxn],dep[maxn],fp[maxn],top[maxn],son[maxn],sz[maxn];
int head[maxn],tot,n,m,a[maxn],mod,root,p[maxn],cnt;
ll sum[maxn<<2],laz[maxn<<2];

int read(){
    int ans=0; char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
void add(int u,int v) {
    e[tot].v=v; e[tot].nex=head[u];
    head[u]=tot++;
}
void dfs1(int u) {
    sz[u]=1,son[u]=0;
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=fa[u]) {
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs1(v);
            if(sz[v]>sz[son[u]])son[u]=v;
            sz[u]+=sz[v];
        }
    }
}

void dfs2(int u,int tp) {
    p[u]=++cnt;
    fp[p[u]]=u;
    top[u]=tp;
    if(son[u])dfs2(son[u],tp);
    for(int i=head[u]; ~i; i=e[i].nex) {
        int v=e[i].v;
        if(v!=son[u]&&v!=fa[u])dfs2(v,v);
    }
}
void deal(int l,int r,int rt,ll v){
    laz[rt]+=v,sum[rt]+=(ll)(r-l+1)*v;
}
void push_up(int rt){
    sum[rt]=sum[lson]+sum[rson];
}
void build(int l,int r,int rt){
	if (l==r){
		sum[rt]=a[fp[l]];
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,lson);
	build(mid+1,r,rson);
	push_up(rt);
}

void push_down(int l,int r,int rt){
    if(laz[rt]){
        int mid=(l+r)/2;
        deal(l,mid,lson,laz[rt]);
        deal(mid+1,r,rson,laz[rt]);
        laz[rt]=0;
    }
}

void update(int ql,int qr,int l,int r,int rt,ll v){
	if (l>=ql&&r<=qr){
        deal(l,r,rt,v);
		return;
	}
	push_down(l,r,rt);
	int mid=(l+r)/2;
	if(mid>=ql) update(ql,qr,l,mid,lson,v);
    if(mid<qr) update(ql,qr,mid+1,r,rson,v);
	push_up(rt);
}

void change(int x,int y,ll v){
	int fx=top[x],fy=top[y];
	while (fx!=fy){
		if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
		update(p[fx],p[x],1,n,1,v);
		x=fa[fx],fx=top[x];
	}
	if (dep[x]>dep[y]) swap(x,y);
	update(p[x],p[y],1,n,1,v);
}

ll query(int ql,int qr,int l,int r,int rt){
	if (l>=ql&&r<=qr) {
        return sum[rt];
	}
	push_down(l,r,rt);
	ll now=0;
    int mid=(l+r)/2;
	if(mid>=ql) now=(now+query(ql,qr,l,mid,lson))%mod;
    if(mid<qr) now=(now+query(ql,qr,mid+1,r,rson))%mod;
	return now;
}

ll fin(int x,int y){
	ll now=0;
	int fx=top[x],fy=top[y];
	while (fx!=fy){
		if (dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
		now+=query(p[fx],p[x],1,n,1),now%=mod;
		x=fa[fx],fx=top[x];
	}
	if (dep[x]>dep[y]) swap(x,y);
	now=(now+query(p[x],p[y],1,n,1))%mod;
	return now;
}

int main(){
    int x,y,op;
    memset(head,-1,sizeof(head));
	n=read(),m=read(),root=read(),mod=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n-1) x=read(),y=read(),add(x,y),add(y,x);
	dfs1(root);
	dfs2(root,root);
	build(1,n,1);
	ll w;
	while (m--){
		op=read(),x=read();
		if(op==1){
            y=read();
            scanf("%lld",&w);
            change(x,y,w);
		}
		else if(op==2){
            y=read();
            printf("%lld\n",fin(x,y));
		}
		else if(op==3){
            scanf("%lld",&w);
            update(p[x],p[x]+sz[x]-1,1,n,1,w);
		}
		else{
            printf("%lld\n",(query(p[x],p[x]+sz[x]-1,1,n,1))%mod);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值