【Nowcoder】点权和 好骚的思维

2023-10-09 22:40
文章标签 思维 nowcoder 点权 好骚

本文主要是介绍【Nowcoder】点权和 好骚的思维,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

链接:https://ac.nowcoder.com/acm/problem/14393
来源:牛客网
 

题目描述

给你一棵树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权和.

输入描述:

第一行两个数n和m
第二行n-1个数,第i个数fa[i + 1]表示i + 1点的父亲编号,保证fa[i + 1]<i + 1
第三行m个数,每个数x依次表示这次操作的点是x

输出描述:

输出一个数,即这m次操作的答案的hash值
如果是第i次操作,这次操作结果为ans,则这个hash值加上
i * ans
输出hash值对19260817取模的结果

 

题解:

我试图去遍历邻接表(以为是水题),结果T飞了呀——m1e7,随便出点数据就可以卡了。

看一下正解:

用一个数组表示,当前这个点操作了几次,那么就如上图所示,绿色的点操作x次对此次操作的贡献即为2*x,蓝色的点为1*x。

很显然x的操作次数的贡献为:x的度数+1。

所以显然需要维护邻接点,但是这个邻接点不太好维护,考虑树的性质:一个点的父亲节点有且只有一个。

那么就想到维护 父亲节点。


首先解释一下下面所用到的所有数组:

tag[x] ,x节点被操作了几次

ftag[x],x节点作为被操作节点的父节点的次数

gftag[x],x节点作为被操做节点爷爷节点的次数


设tag[i]表示第i个节点操作了多少次,那么我们把问题分解开,也就是一个节点向下的贡献(儿子及孙子)与向上的贡献之和(父亲及爷爷)最后再加上这个点的贡献。

1.考虑向下的贡献:

怎么知道x有几个儿子节点呢被操作了呢,因为树的父亲节点只有一个,所以可以在对儿子进行操作时,用一个数组ftag[i]辅助,ftag[i]表示i作为父节点一共被操作了多少次,反过来也就是说ftag[i]表示i节点的所有儿子的贡献。

例如对x点进行操作那么:ftag[fa[x]]++

同理,当对孙子进行操作时考虑爷爷的贡献。gftag[i]表示i的所有孙子节点的的贡献

所以向下的贡献也就非常容易算了:ftag[x]*2+gftag[x]

2.考率向上的贡献:

因为父亲只有一个:那么答案首先要加上tag[fa[x]],表示父亲被操作了多少次。

接下来就是爷爷的贡献:tag[fa[fa[x]]]

但是这时候注意,向上的贡献没有考虑完全:可能一个点y是x的兄弟节点,如果y被操作了的话,x的父亲节点也会被更新,也就是说父亲节点作为父亲节点的时候也有1的贡献。所以答案还需要加上ftag[fa[x]]但是此时父亲节点作为父亲节点时候的贡献包含作为x节点父亲的贡献,而不完全是兄弟节点的。所以ftag[fa[x]]-tag[x]是父亲作为兄弟节点的贡献。

所以向上的贡献为:tag[fa[fa[x]]]+tag[fa[x]]*2+ftag[fa[x]]]-tag[x]

3.最后考虑自己对所有邻接点的贡献 :in[i]*tag[x]

所以每次操作后的结果就是 上述所有贡献之和,可以发现答案完全可以用Om的复杂度去维护

代码:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<stdio.h>
#include<algorithm>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<int,int> pp;
const ll INF=1e18;
const int maxn=5e5+18;
const int mod=19260817;
inline bool read(ll &num)
{char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll tag[maxn];
ll ftag[maxn];
ll gftag[maxn];
int fa[maxn];
ll in[maxn];
int main()
{read(n);read(m);for(int i=2;i<=n;i++){int x;scanf("%d",&x);fa[i]=x;in[i]++;in[x]++;}ll ans=0;for(int i=1;i<=m;i++){int x;scanf("%d",&x);ll temp=0;tag[x]=(tag[x]+1)%mod;///当前节点影响加1if(fa[x]){///存在父亲节点 该父亲节点被儿子节点影响了一次ftag[fa[x]]=(ftag[fa[x]]+1)%mod;///fa[x]作为父节点的次数++temp=(temp+tag[fa[x]]*2+(ftag[fa[x]]-tag[x]))%mod;///父亲节点被操作的次数 对答案的贡献为*2}if(fa[fa[x]]){///存在爷爷节点gftag[fa[fa[x]]]=(gftag[fa[fa[x]]]+1)%mod;temp=(temp+tag[fa[fa[x]]])%mod;///爷爷节点对该点的影响为1}temp=(temp+(in[x]+1)*tag[x]+ftag[x]*2+gftag[x])%mod;ans=(ans+i*temp%mod)%mod;}printf("%lld\n",(ans)%mod);return 0;
}

总结:

这么骚的操作一定要学!

1.树上操作距离小于等于1时的贡献直接考虑父亲节点 儿子节点 孙子节点 爷爷节点 及兄弟节点的贡献即可,并且将儿子与孙子节点的贡献压缩。

2.如果每次操作不+1,而是改成+x,其实道理都一样,不过把上述+1的题目都改为+x即可。

这篇关于【Nowcoder】点权和 好骚的思维的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/176082

相关文章

最大流=最小割=最小点权覆盖集=sum-最大点权独立集

二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。 在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。   二分图最小点权覆盖     从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。 建模:     原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t

颠覆你的开发模式:敏捷思维带来的无限可能

敏捷软件开发作为现代软件工程的重要方法论,强调快速响应变化和持续交付价值。通过灵活的开发模式和高效的团队协作,敏捷方法在应对动态变化和不确定性方面表现出色。本文将结合学习和分析,探讨系统变化对敏捷开发的影响、业务与技术的对齐以及敏捷方法如何在产品开发过程中处理持续变化和迭代。 系统变化对敏捷软件开发的影响 在敏捷软件开发中,系统变化的管理至关重要。系统变化可以是需求的改变、技术的升级、

0906作业+思维导图梳理

一、作业: 1、创捷一个类似于qq登录的界面 1)源代码 #include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);//QPushbutton:登录、退出this->join = new QP

[机缘参悟-222] - 系统的重构源于被动的痛苦、源于主动的精进、源于进化与演进(软件系统、思维方式、亲密关系、企业系统、商业价值链、中国社会、全球)

目录 前言:系统的重构源于被动的痛苦、源于主动的精进、源于进化与演进 一、软件系统的重构 1、重构的定义与目的 2、重构的时机与方法 3、重构的注意事项 4、重构的案例分析 二、大脑思维的重构 1、大脑思维重构的定义 2、大脑思维重构的方法 3、大脑思维重构的挑战与前景 三、认知的重构 1、定义 2、目的 3、方法 四、实例 五、总结 四、婚姻家庭的重构 1、婚

每日一题~cf 970 div3 (A思维,B小模拟,C二分,D排列数建图成环,E 26个字母暴力+前缀和,F 逆元,G 数论gcd )

A 题意: 有 a 个1 ,b 个2.问是否能将这些数划分为两个数值相等的集合。 输出 YES 或者 NO —————— 问题等价于 将数组 分成两个数值相同的数组。所以sum 应该是偶数。也就是说 1 的个数是偶数。在i1的个数是偶数的情况下,将 2 分成两份,如果2 的个数是偶数,OK。如果是奇数那么需要1来补齐,如果1 的个数大于等于2那么可以补齐。(1 的个数是偶数,需要2个1来补齐,剩下

散户炒股票为什么进步慢,学习程序化交易思维

炒股自动化:申请官方API接口,散户也可以 python炒股自动化(0),申请券商API接口 python炒股自动化(1),量化交易接口区别 Python炒股自动化(2):获取股票实时数据和历史数据 Python炒股自动化(3):分析取回的实时数据和历史数据 Python炒股自动化(4):通过接口向交易所发送订单 Python炒股自动化(5):通过接口查询订单,查询账户资产 散户炒股的常见难题

数业智能心大陆告诉你如何培养孩子的批判性思维?

现今的教育体系自小学起便强调培养孩子的批判性思维,这种能力被视为在复杂世界中生存和发展的关键。在当今信息爆炸的时代,它能让我们在海量信息中辨别真伪、深入思考并做出明智决策。如今,如数业智能心大陆产出的AI 心理咨询平台的出现为培养孩子批判性思维提供了新可能,其通过互动引导孩子思考,助力孩子提升批判性思维能力。 什么是批判性思维呢? 批判性思维是一种思考方式,它能够使我们在接收信

华为OD机试 - 最优结果的a数组数量 - 贪心思维(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(E卷+D卷+A卷+B卷+C卷)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。 一、题目描述

互联网思维总结

目录 互联网八大思维 一 互联网思维 一 用户思维 二 产品思维 三 免费思维 四 社群思维 五 大数据思维 六 自媒体思维 七 跨界思维 八 平台思维 总结 互联网八大思维 简要列举以下思维,用户思维,社会化思维,大数据思维,简约思维,极致思维,跨界思维,流量思维,迭代思维,平台思维。 任何企业都可以找到一个竞争对手打,但是有一个对手是打不赢的,就是趋势,趋势一

0904作业+思维导图

一、作业 (将昨天的作业修改为标准模板类的) 1、代码 #include <iostream>#include <stack>using namespace std;//队列模板类template<typename T>class Queue{private:int max; //队列最大容量int num; //队列内元素数T *ptr; //容器