洛谷P3384(樹鏈剖分+線段樹)

題目鏈接:https://www.luogu.org/problemnew/show/P3384

思路:樹鏈剖分模板題,至於線段樹,寫這個的應該都會線段樹纔對emmm。

#pragma GCC optimize(2)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(998244353)
#define pb push_back
#define eps 1e-12
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
ll n,m,r,p,a[200008],tot,x,y,fa[200008],son[200008],sz[200008],head[200008],deep[200008],id[200008],b[200008],cnt,top[200008],z,op;
struct as{
    ll l,r,su,lz;
}tr[200007<<2];
struct node{
int next,to;}e[300008];
void add1(int a,int b)
{
    e[tot].next=head[a];
    e[tot].to=b;
    head[a]=tot++;
}
void push(int d){tr[d].su=(tr[lc].su+tr[rc].su)%p;}
void build(int d,int l,int r)
{
    tr[d].l=l,tr[d].r=r,tr[d].lz=0;
    if(l==r)  {tr[d].su=b[l]%p;return;}
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    push(d);
}
void pushh(int d)
{
    if(tr[d].lz==0) return;
    tr[lc].lz=(tr[lc].lz+tr[d].lz)%p,tr[rc].lz=(tr[rc].lz+tr[d].lz)%p;
    tr[lc].su=(tr[lc].su+tr[d].lz*(tr[lc].r-tr[lc].l+1))%p;
    tr[rc].su=(tr[rc].su+tr[d].lz*(tr[rc].r-tr[rc].l+1))%p;
    tr[d].lz=0;
}
void add(int d,int l,int r,ll pos)
{
    if(tr[d].l==l&&tr[d].r==r)
    {
        tr[d].lz=(tr[d].lz+pos)%p;
        tr[d].su=(tr[d].su+pos*(r-l+1))%p;
        return;
    }
    pushh(d);
    int mid=(tr[d].l+tr[d].r)>>1;
    if(mid>=r)  add(lc,l,r,pos);
    else if(l>mid)  add(rc,l,r,pos);
    else  add(lc,l,mid,pos),add(rc,mid+1,r,pos);
    push(d);
}
ll query(int d,int l,int r)
{
    if(tr[d].l==l&&tr[d].r==r)  {return tr[d].su;}
    pushh(d);
    int mid=(tr[d].l+tr[d].r)>>1;
    if(mid>=r)  return query(lc,l,r);
    else if(l>mid)  return query(rc,l,r);
    else  return (query(lc,l,mid)+query(rc,mid+1,r));
    push(d);
}
void dfs(int u,int f,int de)
{
    sz[u]=1,fa[u]=f,deep[u]=de;
    int maxson=0;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==f) continue;
        dfs(v,u,de+1);
        sz[u]+=sz[v];
        if(sz[v]>maxson) son[u]=v,maxson=sz[v];
    }
}
void dfs1(int u,int tfa)
{
    id[u]=++cnt,b[cnt]=a[u],top[u]=tfa;
    if(!son[u]) return;
    dfs1(son[u],tfa);
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa[u]||v==son[u]) continue;
        dfs1(v,v);
    }
}
ll Query(int l,int r)
{
    ll ans=0;
    while(top[l]!=top[r])
    {
        if(deep[top[l]]<deep[top[r]]) swap(l,r);
        ans+=query(1,id[top[l]],id[l]);
        l=fa[top[l]];
    }
    if(deep[l]<deep[r]) swap(l,r);
    ans+=query(1,id[r],id[l]);
    return (ans%p);
}
void Add(int l,int r,ll z)
{
    while(top[l]!=top[r])
    {
        if(deep[top[l]]<deep[top[r]]) swap(l,r);
        add(1,id[top[l]],id[l],z);
        l=fa[top[l]];
    }
    if(deep[l]<deep[r]) swap(l,r);
    add(1,id[r],id[l],z);
}
int main()
{
    cin.tie(0);
    cout.tie(0);
    REW(head,-1);
    cin>>n>>m>>r>>p;
    FOR(i,1,n) sl(a[i]);
    FOR(i,1,n-1) sl(x),sl(y),add1(x,y),add1(y,x);
    dfs(r,0,1),dfs1(r,r);
    build(1,1,n);
    while(m--)
    {
        sl(op);
        if(op==1) sl(x),sl(y),sl(z),z%=p,Add(x,y,z);
        else if(op==3) sl(x),sl(z),z%=p,add(1,id[x],id[x]+sz[x]-1,z);
        else if(op==2) sl(x),sl(y),cout<<(Query(x,y)%p)<<endl;
        else if(op==4) sl(x),cout<<(query(1,id[x],id[x]+sz[x]-1)%p)<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章