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

我是小丑。

有没有一种恰好将所有 ≤ 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"; } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529980.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(30)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示