牛客小白月赛9 D、书上求和(DFS序+线段树)

题目链接
题目大意:
图片说明
图片说明
输入:
5 5
0 0 0 0 0
1 2
1 3
3 4
3 5
1 1 3
1 3 7
1 4 5
1 5 6
2 1
输出:
599

总体思路:
因为是对一棵子树整体进行操作+k,所以我们可以用DFS序列将一棵树转化为一个序列,然后再在序列中用线段树来进行区间操作。线段树维护平方和也是老套路了。
图片说明
代码实现:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=23333;
ll n,q;
ll a[100005];//记录每个点的初始值
//int b[100005];
ll dfsxu[100005];//DFS序
ll s[100005],e[100005];//s进点序,e出点序,一个子树根节点的进点序和出点序的序列解释这棵子树的DFS序
ll h[100005],t[100005*2],ne[100005*2];
ll inx;
ll op,x,y;
ll l,r;
struct ty{
    ll l,r;
    ll psum;//记录平方和 
    ll sum;//记录一次方和 
    ll lazy;//记录增加的K 
}; 
ty tr[100005*4]; 

void add(ll x,ll y){
    t[inx]=y;ne[inx]=h[x];h[x]=inx++; 
    return ;
}

ll id,len;
void dfs(ll u,ll fa){
    s[u]=++id;
    dfsxu[++len]=u;
    for(ll i=h[u];i!=-1;i=ne[i]){
        ll to=t[i];
        if(to==fa) continue;
        dfs(to,u);
    }
    e[u]=id;
    return ;
}

void pushup(ll u){
    tr[u].psum=(tr[u<<1].psum+tr[u<<1|1].psum)%mod;
    tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%mod;
    tr[u].lazy=0;
    return ;
}

void build(ll u,ll l,ll r){
    tr[u].l=l;tr[u].r=r;
    tr[u].lazy=0;
    if(l==r){
        tr[u].psum=a[dfsxu[l]]*a[dfsxu[l]]%mod;
        tr[u].sum=a[dfsxu[l]];
        tr[u].lazy=0;
        return ;
    }
    ll mind=(l+r)>>1;
    build(u<<1,l,mind);
    build(u<<1|1,mind+1,r);
    pushup(u);
    return ;
} 

void pushdown(ll u){
    if(!tr[u].lazy) return ;
    tr[u<<1].psum=(tr[u<<1].psum%mod+2*tr[u].lazy*tr[u<<1].sum%mod+(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy*tr[u].lazy%mod)%mod;
    tr[u<<1|1].psum=(tr[u<<1|1].psum%mod+2*tr[u].lazy*tr[u<<1|1].sum%mod+(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy*tr[u].lazy%mod)%mod;
    tr[u<<1].sum=(tr[u<<1].sum+(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy%mod)%mod;
    tr[u<<1|1].sum=(tr[u<<1|1].sum+(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy%mod)%mod;
    tr[u<<1].lazy=(tr[u<<1].lazy+tr[u].lazy)%mod;
    tr[u<<1|1].lazy=(tr[u<<1|1].lazy+tr[u].lazy)%mod;
    tr[u].lazy=0;
    return ;
}

void modify(ll u,ll l,ll r,ll k){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].psum=(tr[u].psum%mod+2*k*tr[u].sum%mod+(tr[u].r-tr[u].l+1)*k*k%mod)%mod;
        tr[u].sum=(tr[u].sum+(tr[u].r-tr[u].l+1)*k%mod)%mod;
        tr[u].lazy=(tr[u].lazy+k)%mod;
        return ;
    }
    pushdown(u);
    ll mind=(tr[u].l+tr[u].r)>>1;
    if(l<=mind) modify(u<<1,l,r,k);
    if(r>mind) modify(u<<1|1,l,r,k);
    pushup(u);
    return ;
}

ll query(ll u,ll l,ll r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].psum%mod;
    } 
    pushdown(u);
    ll mind=(tr[u].l+tr[u].r)>>1;
    ll ans=0;
    if(l<=mind) ans=(ans+query(u<<1,l,r))%mod;
    if(r>mind) ans=(ans+query(u<<1|1,l,r))%mod;
    pushup(u);
    return ans;
}

int main(){
    for(ll i=0;i<=100001;i++) h[i]=-1;
    scanf(" %lld %lld",&n,&q);
    for(ll i=1;i<=n;i++) scanf(" %lld",&a[i]);
    for(ll i=1;i<n;i++){
        scanf(" %lld %lld",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,-1);//求DFS序
    build(1,1,n);//建线段树 
    for(ll i=1;i<=q;i++){
        scanf(" %lld",&op);
        if(op==1){
            scanf(" %lld %lld",&x,&y);
            modify(1,s[x],e[x],y);
        }
        else{
            scanf(" %lld",&x);
            printf("%lld\n",query(1,s[x],e[x])%mod);
        }
    }
    return 0;
} 
全部评论

相关推荐

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