题目传送门(内部题103)


输入格式

  第一行一个数$n$,表示结点的个数。
  第二行$n–1$个数,第$i$个数是$p[i+1]$。$p[i]$表示结点$i$的父亲是$p[i]$。数据保证$p[i]<i$。
  第三行$n$个数,$a[1],a[2],...,a[n]$,表示关卡表。数据保证这是一个排列。
  第四行$n$个数,$x[1],x[2],...,x[n]$,表示结点的权值。


输出格式

  输出一个数表示答案。即对于所有可能的回合,你们能获得的总收益是多少。


数据范围与提示

  对于$20\%$的数据,满足$n\leqslant 100$。
  对于$40\%$的数据,满足$n\leqslant 2,000$。
  对于$60\%$的数据,满足$n\leqslant 50,000$。
  对于另外$20\%$的数据,排列$a[i]$是用如下的算法生成的:从一号点开始对树做$dfs$,到达一个节点的时候输出这个结点。
  对于$100\%$的数据,满足$1\leqslant n\leqslant 200,000,0\leqslant x[i]\leqslant 100,000,p[i]<i$,$a[i]$是一个排列。


题解

其实另外$20\%$的数据就是正解的一个引导。

显然对于这个部分分无非就是输出每一个点的子节点的$size$相互之间的乘积和乘上这个点的$x$值即可。

那么考虑正解。

用$dsu\ on\ tree$思想,每个节点继承儿子中最重的节点的信息,其他儿子暴力合并;用两个数组记录当前位置是否是一个极长区间的左(右)端点并记录另一个端点的位置,加入一个节点时尝试合并左右信息并统计合并后的方案数即可。

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[200000];
int head[200001],cnt;
int n;
int a[200001],val[200001],size[200001],son[200001],l[200001],r[200001],vis[200001],dfn[200001],now;
long long ans;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
dfs(e[i].to);
size[x]+=size[e[i].to];
if(size[son[x]]<size[e[i].to])son[x]=e[i].to;
}
}
long long insert(int x)
{
vis[a[x]]=now;
if(vis[a[x]+1]!=now)l[a[x]+1]=r[a[x]+1]=0;
if(vis[a[x]-1]!=now)l[a[x]-1]=r[a[x]-1]=0;
long long L=l[a[x]-1],R=r[a[x]+1],len=l[a[x]-1]+r[a[x]+1]+1;
l[a[x]]=L+1;r[a[x]]=R+1;l[a[x]+R]=r[a[x]-L]=len;
return len*(len+1)/2-L*(L+1)/2-R*(R+1)/2;
}
long long ask(int x)
{
long long res=insert(x);
for(int i=head[x];i;i=e[i].nxt)
res+=ask(e[i].to);
return res;
}
int dfs(int x,int opt)
{
now=dfn[x]=x;
long long res=0,num=0,flag=0;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=son[x])res-=dfs(e[i].to,0);
if(son[x])
{
flag=dfs(son[x],1);
num+=flag;
now=dfn[x]=dfn[son[x]];
}
num+=insert(x);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=son[x])num+=ask(e[i].to);
ans+=(res+num-flag)*val[x];
return num;
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++){int x;scanf("%d",&x);add(x,i);}
for(int i=1;i<=n;i++){int x;scanf("%d",&x);a[x]=i;}
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
dfs(1);
dfs(1,1);
printf("%lld",ans);
return 0;
}

rp++

[CSP-S模拟测试]:射手座之日(dsu on tree)的更多相关文章

  1. 联赛模拟测试10 C. 射手座之日

    题目描述 分析 方法一(线段树) 线段树维护的是以当前节点为左端点的区间的贡献 而区间的右端点则会从 \(1\) 到 \(n\) 逐渐右移 当我们把右端点从 \(i-1\) 的位置扩展到 \(i\) ...

  2. csp-s模拟测试94

    csp-s模拟测试94 一场简单题,打爆了.$T1$脑抽分解质因数准备分子分母消,想了半天发现$jb$互质直接上天,果断码了高精滚蛋.$T2$无脑手玩大样例,突然灵光一闪想到映射到前$K$大小的区间, ...

  3. [考试反思]1030csp-s模拟测试94:未知

    排名也未知.第1或第5. 分数也未知,300或260. 人生真是大起大落... 啊啊啊啊啊我好感动啊竟然重测了一次----- 评测机怎么测怎么RE,本机怎么测怎么AC(任意编译指令,任意评测平台) 结 ...

  4. [CSP-S模拟测试94]题解

    A.凉宫春日的忧郁 高精硬上似乎跑不过,其实可以都取个$log$.那么只需要比较$y\times log ^x$和$\sum \limits _{i=1}^y log^i$就好了. #include& ...

  5. Android单元测试与模拟测试详解

    测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabri ...

  6. [开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)

    目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具 ...

  7. 安装nginx python uwsgi环境 以及模拟测试

    uwsgi帮助文档: http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html http://uwsgi-docs.re ...

  8. 利用Python中的mock库对Python代码进行模拟测试

    这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下     ...

  9. 转 C#实现PID控制的模拟测试和曲线绘图

    C#实现PID控制的模拟测试和曲线绘图   本文分两部分,一部分是讲PID算法的实现,另一部分是讲如何用动态的曲线绘制出PID运算的结果. 首先,PID算法的理论模型请参考自动控制理论,最早出现的是模 ...

随机推荐

  1. Sharepoint 开启App 配置App

    如果没有Enable app,打开app store的时候出出现错误: Sorry, apps are turned off. If you know who runs the server, tel ...

  2. 题解 P2859 【[USACO06FEB]摊位预订Stall Reservations】

    题目链接: https://www.luogu.org/problemnew/show/P2859 思路: 首先大家会想到这是典型的贪心,类似区间覆盖问题的思路,我们要将每段时间的左端点从小到大排序, ...

  3. linux系统TCP协议之Send(转)

    tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数 ...

  4. smbfs

    Hi I tried to mount a network share (smbfs) but it complains about the lack of kernel support. To so ...

  5. Linux Shell Web超级终端工具shellinabox

    Shell是Linux内核应用程序,是指“为使用者提供操作界面”的软件,也是命令解析器,它类似于Windows操作系统DOS下的cmd.exe应用程序.它接收用户命令,然后调用相应的应用程序,用户一般 ...

  6. oracle下关于table的常用sql整理

    创建表,create TABLE table( 列名称1 数据类型1, 列名称2 数据类型2, 列名称3 数据类型3, ......); eg: create table TABLE_24751( i ...

  7. python文件操作:文件处理与操作模式

    一,文件处理的模式基本概念 #coding:utf-8 # 一: 文件处理的三个步骤 # 1. 打开文件拿到文件对象(文件对象====>操作系统打开文件====>硬盘) # f=open( ...

  8. P3731 二分图匹配必经边

    题意经过一番转换变成了 让你在一个二分图上删一条边使得二分图的最大独立集大小至少+1 二分图的最大独立集=点数-最小点覆盖(最大匹配) 点数是固定不变的 所以我们要减少最大匹配数 则删掉的哪一条边必须 ...

  9. Layui 监听 复选框 提交表单

    表单数据这一块 layui 做的是真的不好,无论是在渲染还是在交互方面,每次都要自己来重新实现代码 #贴上代码 <!DOCTYPE html> <head> <meta ...

  10. ubuntu学习笔记-tar 解压缩命令详解(转)

    tar 解压缩命令详解 -c: 建立压缩档案 -x:解压-t:查看内容-r:向压缩归档文件末尾追加文件-u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能 ...