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

26 篇文章 0 订阅
21 篇文章 0 订阅

我是小丑。

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

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

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

复杂度 O ( n d ) 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";
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值