2022牛客多校六 B&&J

106 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

B-Eezie and Pie (dfs)

image.png

样例输入:

10 1 2 2 3 2 4 3 5 4 6 4 7 1 8 8 9 8 10 0 0 1 2 2 5 3 1 0 2 样例输出: 6 6 2 3 1 1 1 2 1 1 题意:给定一棵有根树,根为1,每个节点可以为它的 0 ~ 𝑑[𝑖] 级祖先贡献 1 的价值。求最终每个点的价值。

分析:对于每个子节点可以先找到他的第一个不能贡献的祖先节点v,并将loss[v]减1,那么在v之上的祖先节点也无法得到该节点的贡献,所以也就是说loss是可以上传的,那么loss[v]的含义就是说以v为根的子树中不能给v带来贡献的子节点数目。所以我们就可以得到,每个节点的最终价值就是以他为根的子树中的节点个数减去以他为根的子树中不能给他带来贡献的子节点数目,也就是cnt[]+loss[]

我们可以直接在dfs过程中求出每一个节点的若干级父亲节点,这样方便我们来查找d[i]+1级父亲,也就是该节点第一个不能贡献的祖先节点,查询的复杂度就是log级别,所以总的复杂度就是nlogn级别。

细节见代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=5e6+10;
int h[N],e[N],idx,ne[N];
int fu[N][21],cnt[N],loss[N],w[N];
long long f[N];
void add(int x,int y)
{
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
void dfs(int x,int fa)
{
	fu[x][0]=fa;
	cnt[x]=1;
	for(int i=1;i<=20;i++)
		fu[x][i]=fu[fu[x][i-1]][i-1];
	for(int i=h[x];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa) continue;
		dfs(j,x);
		cnt[x]+=cnt[j];
		loss[x]+=loss[j];
	}
	int ff=x;
	for(int i=20;i>=0;i--)
		if(w[x]>>i&1) ff=fu[ff][i];
	loss[fu[ff][0]]--;
	f[x]=cnt[x]+loss[x];
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)	h[i]=-1;
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&w[i]);
	dfs(1,-1);
	for(int i=1;i<=n;i++)
		printf("%d ",f[i]);
	return 0; 
}

J-Number Game(简单推理)

image.png

样例输入:

3 2 4 3 1 2 4 3 2 4 2 2 0 样例输出:

Yes No Yes 题意:给定a,b,c,x,我们可以对a和b和c这三个数进行操作,我们可以把b变成a-b,也可以把c变成b-c,操作次数不受限制,问我们能不能把c变成x。

分析:

我们发现对b进行操作只能得到两种结果,一种是a-b,另一种是a-(a-b)=b,也就是b自己,所以无论对b进行多少次操作,b只能有这两种值,所以我们可以直接让a-=b,然后等价于c有两种操作,一种是把c变为a-c,另一种就是题目中所描述的,把c变为b-c,通过简单模拟我们发现我们不应该连续两次用同一个数减c,因为那样相当于没减,所以我们只能是交替着减c,那么也就有两种情况,一种是a-(……(b-(a-(b-(a-c))))),另一种是b-(……(a-(b-(a-(b-c))))),然后通过化简可以得到第一种情况对应着两个等式,一个是a+k*(a-b)-c=x另一个是k*(a-b)+c=x,第二种情况也对应着两个等式,一个是b+k*(b-a)-c=x,另一个是k*(b-a)+c=x,所以我们只要判断一下这四个等式是否有一个成立就可以了。注意特判a=b的情况

细节见代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=1e4+10;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long a,b,c,x;
		scanf("%lld%lld%lld%lld",&a,&b,&c,&x);
		bool flag=false;
		a-=b;
		if(a-b)
		{
			if((x-c)%(a-b)==0) flag=true;
			if((x+c-a)%(a-b)==0) flag=true;
			if((x+c-b)%(b-a)==0) flag=true;
		}
		else
		{
			if(x-c==0) flag=true;
			if(x+c-a==0) flag=true;
			if(x+c-b==0) flag=true;
		}
		if(flag) puts("Yes");
		else puts("No");
	}
	return 0;
}