做题小结3

第一个题目

前言

这次我题目也是读了很久 那个p数组也看来很久明白。。

根明显是输入等于自己的那个点

这个题的构造 其实我么可以贪心的+1的叠加

输出只需要减去父节点的就行

明显正确

之前做过类似的,对于这道题目最重要是树链的抛分了

上次都没注意这个技巧这么实用 我一开始是想写出完整的链抛分 不打vis标记 后面一算时间 这个肯定要超时的 毕竟叶子达到上万层深度是很简单的,所以还是要打vis标记

然后打了vis 对抛分的vector数组分析

均摊下来时间复杂度就是on呀

	for (int i = 1; i <= n; i++) {
		cin >> p[i];   
		w[p[i]] = num;
		num++;
	}
	if(p[1]!=die){
		cout<<-1<<endl;
		init();
		return;
	}
	for (int i = 1; i <= n; i++) {
		if (fa[i] == 0) {
			int x = i;	step=0;	
			map<int, bool>ma;
			while (vis[x] == 0) {
				ans[++step] = x;
				ma[x] = 1;
				vis[x] = 1;
				x = a[x];			
			}
			if (ma[a[i]] == 0)
				ans[++step] = a[i]; 
			for (int j = 2; j <= step; j++) {
				if (w[ans[j - 1]]> w[ans[j]])continue;
				else {
					cout <<-1<<endl;
					init();
					return ;
				}
			}
			for(int j=1;j<=step;j++)ans[j]=0;
		}
	}

然后我这边多加了一点小细节 每次把父节点压入如果没压的话 毕竟我们用了vis数组 如果父节点被访问了 那他自己一个点 我们对p数组就没法验证正确性了

不过这样子做 加一个点其实还是不够的 两个点没有问题 那父节点的父节点p数组有问题 怎么办 此时的这个点已经被vis了 又加不进去验证,怎么办

其实这个时候 我们直接在答案那部分验证正确性就可以了 最终只有经过层层验证 才输出

	for(int i=1;i<=n;i++)	
	{
		if(w[i]-w[a[i]]>=1||i==die)
			v.push_back(w[i]-w[a[i]]);
		else {
			cout<<-1<<endl;
			return ;
		}
	}

第二个题目

第三个题目

分别是easy hard 版本

这是两道最短路的好题 我当时在估算时间复杂度出了问题

脑子太死板了 只想到了板子的dj这些 这样挨个对每个朋友进行dj当然要t飞了 我们完全可以把他们看成一个集合 对他们总体跑一次最短路不就行了吗 早靠近叶子的人早达到 使用vis数组判断重复即可 然后最后一一比较距离即可 这是easy版本的做题思路

hard版本 其实代码总体不变 对于逃不出去必输的局

我们要想到 有些朋友他们可以一次性堵好几个路口 有的朋友就没用处或者说重复用处了

我们完全可以这么想 那些朋友往上去堵路口就好了

堵住一个路口 那这个子树都不用访问了 此时答案++ 表示需要一位朋友就行 至于这个子树有多少个朋友我们不管 我们就要一位就行了 注意 这里谈论的基础是在这个人无论如何都没法赢得情况下

于是我们只需要写个dfs就行了

dfs代码如下

void dfs (int x,int fa) {
	if(vis[x])return;
	vis[x]=1;
	for(auto i:e[x])//人写傻了 第一发交上去e[1] 搞半天不知道错哪了
	{
		if(i==fa)continue;
		if(vis[i])continue;
		depth[i]=depth[x]+1;
		if(diss[i]>depth[i])
			dfs(i,x);
		else 
		{  ans++,vis[i]=1;
		//	cout<<i<<" ";
		}
	}
	
} 

总的代码不放了 太长了 可以去提交记录看看

别的就没啥说了

posted @ 2025-04-16 19:47  LteShuai  阅读(7)  评论(0)    收藏  举报