【学习笔记】「JOISC 2022 Day3」洒水器

文章介绍了一种在树结构中对每层节点进行标记的方法,确保每个节点被标记一次。通过从根节点开始,沿着祖先路径传递信息,动态更新节点的标记状态。这种方法适用于处理树的层次操作,且不依赖于特定的数据结构,具有线性时间复杂度O(nd)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我是小丑。

有没有一种恰好将所有≤d\le dd的点都标记一次的打标方法?

答案是有的。设fi,df_{i,d}fi,d表示以iii为根的子树,第ddd层的儿子打上的标记。然后发现,从xxx出发往上爬到祖先yyy,假设到yyy点时上还有ddd步可以走,那么就把以yyy为根的子树的第ddd层和第d−1d-1d1层打上标记。

这样每个点恰好标记一次。厉害。不需要用到任何数据结构。

复杂度O(nd)O(nd)O(nd)

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+55;
int n,L,Q;
ll f[N][45],h[N],fa[N];
vector<int>G[N];
//joker
void dfs(int u,int topf){
    fa[u]=topf;
    for(auto v:G[u]){
        if(v!=topf){
            dfs(v,u);
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>L;
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        G[u].pb(v),G[v].pb(u);
    }
    for(int i=n+1;i<=n+40;i++){
        G[i].pb(i-1),G[i-1].pb(i);
    }
    for(int i=1;i<=n;i++)cin>>h[i];
    for(int i=1;i<=n+40;i++){
        for(int j=0;j<=40;j++)f[i][j]=1;
    }
    dfs(n+40,0);
    cin>>Q;
    for(int i=1;i<=Q;i++){
        int op;
        cin>>op;
        if(op==1){
            int x,D,W;
            cin>>x>>D>>W;
            while(x&&D>=0){
                f[x][D]=f[x][D]*W%L;
                if(D)f[x][D-1]=f[x][D-1]*W%L;
                x=fa[x],D--;
            }
        }
        else{
            int x,D=0;
            cin>>x;
            ll res=h[x];
            while(x&&D<=40){
                res=res*f[x][D]%L;
                x=fa[x],D++;
            }
            cout<<res<<"\n";
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值