[JOIST 2022] 洒水器 / Sprinkler 题解

[JOIST 2022] 洒水器 / Sprinkler
题意:对一棵树支持 \(m\) 次操作,每次是模意义下 \(k\) 级邻域乘,或者单点查值。\(n \le 2 \times 10^5,k\le 40\)。

注意到距离值非常小,考虑设 \(tag_{x,d}\) 表示节点 \(x\) 的子树中距离为 \(d\) 的点被乘了多少。每次修改操作就从 \(x\) 开始跳祖先节点 \(l\),修改 \(tag_{l,0~d-dis(x,l)}\) 的值,但是这会重复算,令到达 \(l\) 的上一个节点为 \(s\),则 \(tag_{s,0~d-dis(u,l)-1}\) 即 \(tag_{s,0~d-dis(x,s)-2}\) 要除以 \(w\)。但是在 \(s\) 那一轮时 \(tag_{s,0~d-dis(x,s)}\) 都乘了 \(w\),所以最后只有 \(tag_{s,d-dis(x,s)-1}\) 和 \(tag_{s,d-dis(x,s)}\) 需要更新。注意当跳到根节点时必须暴力更新所有的深度范围。

查询也是跳祖先,最多只要跳 \(40\) 次就好了,因为只有这个距离以内的祖先有贡献。

时间复杂度 \(O(nd)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m,mod;
const int N = 2e5+10;
vector<int>g[N];
int tag[N][41],fa[N],h[N];
void dfs(int x,int f){
    fa[x]=f;
    for(auto v:g[x]){
        if(v==f)continue;
        dfs(v,x);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>mod;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++){
        cin>>h[i];
        for(int j=0;j<=40;j++){
            tag[i][j]=1;
        }
    }
    cin>>m;
    while(m--){
        int op,x,d,w;
        cin>>op;
        if(op==1){
            cin>>x>>d>>w;
            while(d>=0&&x){
                tag[x][d]=(tag[x][d]*w%mod)%mod;
                if(d>=1)tag[x][d-1]=(tag[x][d-1]*w%mod)%mod;
                if(x==1){
                    for(int j=0;j<=d-2;j++){
                        tag[1][j]=(tag[1][j]*w%mod)%mod;
                    }
                }
                x=fa[x];
                d--;
            }
        }else{
            cin>>x;
            int res=h[x];
            for(int d=0;d<=40;d++){
                if(!x)break;
                res=res%mod*tag[x][d]%mod;
                x=fa[x];
            }
            cout<<res<<endl;
        }
    }
    return 0;
}
posted @ 2026-09-22 19:08  farenara_sayowell  阅读(7)  评论(0)    收藏  举报