#Z2322. 买保险
一.题目
二.思路
1.暴力
训练的时候,初看这道题,这不就打个暴力吗?
2.暴力代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,fa,x,y,vis[1000001],ans;
vector<int> vec[1000001];
void dfs(int x,int y)
{
if(y == -1) return ;
vis[x] = 1;
for(int i = 0;i < vec[x].size();i++) dfs(vec[x][i],y - 1);
}
signed main()
{
cin>>n>>m;
for(int i = 2;i <= n;i++)
{
cin>>fa;
vec[fa].push_back(i);
}
while(m--)
{
cin>>x>>y;
dfs(x,y);
}
for(int i = 1;i <= n;i++)
if(vis[i])
ans++;
cout<<ans;
return 0;
}
结果。。。
3.正解
赛后仔细研究了一下,其实也不难,只要借鉴一下线段树lazy标记的思想,打个标记,dfs的时候下传就行了。细节有点多,可以看看代码。
4.代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,fa,x,y,vis[1000001],ans,t[1000001];
vector<int> vec[1000001];
void dfs(int x,int fa,int y)
{
t[x] = max(t[x],y);//因为有可能父节点下传了保险,自己也买了一份保险
if(t[x]) vis[x] = 1;
for(int i = 0;i < vec[x].size();i++)
if(fa != vec[x][i])
{
if(t[x] - 1 >= 0) dfs(vec[x][i],x,t[x] - 1);
else dfs(vec[x][i],x,0);
}
}
signed main()
{
cin>>n>>m;
for(int i = 2;i <= n;i++)
{
cin>>fa;
vec[fa].push_back(i);
vec[i].push_back(fa);
}
while(m--)
{
cin>>x>>y;
y++;
t[x] = max(t[x],y);//因为一个人有可能买多份保险,所以要取其中往后最多的子孙的那一份
}
dfs(1,0,0);
for(int i = 1;i <= n;i++)
if(vis[i])
ans++;
cout<<ans;
return 0;
}
三.结语
如果这篇博客对您有帮助的话,请点个赞支持一下吖!( •̀ ω •́ )✧