做题小结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<<" ";
}
}
}
总的代码不放了 太长了 可以去提交记录看看
别的就没啥说了


浙公网安备 33010602011771号