树链剖分 模板 洛谷p3384

P3384 【模板】树链剖分
1.1K
通过
3.8K
提交
题目提供者HansBug 站长团
标签 高性能
难度 省选/NOI-
时空限制 1s / 128MB
提交 讨论 题解

最新讨论 更多讨论

为啥一个板子的难度设的这么…
哪位大佬来解决下本蒟蒻的疑…
三个点TLE是怎么回事
RE,70分。有大神能帮忙解决…
题目上的不解
90分,最后一个运行错误,大…
题目描述

如题,已知一棵包含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(重要的事情说三遍:记得取模)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N=100005;
int n,m,r,p,tot,dcnt;
int w[N],head[N*2],mp[N];
struct NODE{
    int to,nex;
}ed[N*2];
struct node{
    int fa,son,sz,dep,top,s,e;
}tr[N];//树链剖分
struct Segtree{
   int l,r;
   int sum,lazy;
}tree[4*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<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
void dfs1(int u){
    tr[u].sz=1;
    for(int i=head[u];i;i=ed[i].nex)
     if(ed[i].to!=tr[u].fa){
         tr[ed[i].to].fa=u;
         tr[ed[i].to].dep=tr[u].dep+1;
         dfs1(ed[i].to);
         tr[u].sz+=tr[ed[i].to].sz;
         if(tr[ed[i].to].sz>tr[tr[u].son].sz)
            tr[u].son=ed[i].to;
     }
}
void dfs2(int u,int top){
    tr[u].top=top;
    tr[u].s=++dcnt;
    mp[dcnt]=u;//反向映射
    if(tr[u].son){
        dfs2(tr[u].son,top);
        for(int i=head[u];i;i=ed[i].nex)
            if(ed[i].to!=tr[u].fa&&ed[i].to!=tr[u].son)
              dfs2(ed[i].to,ed[i].to);
    }
    tr[u].e=dcnt;
}
inline void addedge(int x,int y){
    ++tot;
    ed[tot].nex=head[x];
    head[x]=tot;
    ed[tot].to=y;
}
inline void update(int u){
    tree[u].sum=tree[u*2].sum+tree[u*2+1].sum;
    return ;
}
void build(int b,int l,int r){
    tree[b].l=l;
    tree[b].r=r;
    if(l==r){
        tree[b].sum=w[mp[l]];
        return ;
    }
    int mid=l+r>>1;
    build(b*2,l,mid);
    build(b*2+1,mid+1,r);
    update(b);
}
inline void pushdown(int b){
    if(tree[b].lazy){
        if(tree[b].l!=tree[b].r){
            tree[b*2].sum=tree[b*2].sum+tree[b].lazy*(tree[b*2].r-tree[b*2].l+1)%p;
            tree[b*2+1].sum=tree[b*2+1].sum+tree[b].lazy*(tree[b*2+1].r-tree[b*2+1].l+1)%p;
            tree[b*2].lazy+=tree[b].lazy;
            tree[b*2+1].lazy+=tree[b].lazy;
        }
        tree[b].lazy=0;
    }
    return ;
}
void change(int b,int x,int y,int z){
    if(y<tree[b].l||x>tree[b].r) return ;
    if(tree[b].l>=x&&tree[b].r<=y){
        tree[b].lazy+=z;
        tree[b].sum=(tree[b].sum+(tree[b].r-tree[b].l+1)*z)%p;
        return ;
    }
    pushdown(b);
    change(2*b,x,y,z);
    change(2*b+1,x,y,z);
    update(b);
}
inline void add(int x,int y,int z){
    int f1=tr[x].top;
    int f2=tr[y].top;
    while(f1!=f2){
        if(tr[f1].dep<tr[f2].dep)
             swap(f1,f2),swap(x,y);
        change(1,tr[f1].s,tr[x].s,z);
        x=tr[f1].fa;
        f1=tr[x].top;
    }
    if(tr[x].dep<tr[y].dep)
       change(1,tr[x].s,tr[y].s,z);
    else change(1,tr[y].s,tr[x].s,z);
}
long long query(int num,int x,int y)
{
    if(y<tree[num].l||x>tree[num].r)
        return 0;
    if(tree[num].l>=x&&tree[num].r<=y)
        return tree[num].sum;
    pushdown(num);
    return (query(2*num,x,y)+query(2*num+1,x,y))%p;
}
inline int cha(int x,int y)  {
    int f1=tr[x].top,f2=tr[y].top;
    long long ans=0;
    while(f1!=f2)
    {
        if(tr[f1].dep<tr[f2].dep)
            swap(f1,f2),swap(x,y);
        ans=(ans+query(1,tr[f1].s,tr[x].s))%p;
        x=tr[f1].fa;
        f1=tr[x].top;
    }
    if(tr[x].dep<tr[y].dep)
        ans+=query(1,tr[x].s,tr[y].s);
    else
        ans+=query(1,tr[y].s,tr[x].s);
    return ans%p;
}
main(){
    n=read();
    m=read();
    r=read();
    p=read();
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<n;i++){
      int x,y;
      x=read();
      y=read();
      addedge(x,y);
      addedge(y,x);
    }
    dfs1(r);
    dfs2(r,r);
    build(1,1,n);
  for(int i=1;i<=m;i++){
        int ort;
        scanf("%lld",&ort);
        if(ort==1){
            int x,y,z;
            x=read();
            y=read();
            z=read();
          add(x,y,z);
        }
        if(ort==2){
            int x,y;
            x=read();
            y=read();
            printf("%lld\n",cha(x,y)%p);
        }
         if(ort==3){
            int x,z;
            x=read();
            z=read();
            change(1,tr[x].s,tr[x].e,z);
        }
        if(ort==4){
            int x;
            x=read();
            printf("%lld\n",query(1,tr[x].s,tr[x].e)%p);
        }
    }
    return 0;
}

哈哈哈

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务