题目描述

给定一棵\(n\)个点的有根树,根节点编号为\(1\),点有点权。

定义\(d(v)\)表示\(v\)到\(1\)的路径上的边数。

定义\(f(v,u)\)在\(v<u\)且\(v\)和\(u\)任意一个都不是另一个的祖先时为\(1\),否则为\(0\)。

定义\(g(v,u)\)在\(v\)是\(u\)的祖先且\(v\)的权值大于\(u\)的权值时为\(1\),否则为\(0\)。

定义\(h(v,u)\)在\(v\)是\(u\)的祖先且\(v\)的权值小于\(u\)的权值时为\(1\),否则为\(0\)。

你需要将点集分成两个集合\(A\)和\(B\),有\(m\)组询问,每组询问给定了集合\(A\)的大小,求下列表达式的最小值:

\[F(A,B)=\sum_{v\in A,u\in A,v\not=u}f(v,u)+g(v,u)+\sum_{v\in B,u\in B,v\not = u} h(v,u)+\sum_{v\in A}d(v)
\]

输入

第一行两个整数\(n,m\)。

接下来一行\(n\)个整数\(a_i\)表示第\(i\)个点的权值。

接下来\(n−1\)行,第\(i\)行两个整数\(v,u\)表示一条连接\((v,u)\)的边。

接下来\(m\)行,每行一个整数表示\(|A|\)。

输出

共\(m\)行,每行一个整数表示表达式的最小值。

样例

样例输入

4 3
4 1 2 3
1 2
2 3
2 4
0
2
4

样例输出

2
2
9

数据范围

对于\(100\%\)的数据,\(1\leq n,m\leq 500000,0\leq |A|\leq n,1\leq a_i\leq 500000\)。

比第二题又难了不少……(差评,题目难度指数式上升)

这一坨定义看起来好难受啊,考虑转化一下。

首先看\(f\)的意义,发现其实就是\(|A|\)中互不为祖先的点对数,等价于\(C(|A|,2)-\)每个点在\(A\)中的祖先个数的和;\(d\)的意义是深度,也就是\(A\)中所有点在树上的祖先个数的和。

那这两个加起来是什么呢?就是\(C(|A|,2)+\)满足\(u\in A,v\in B\)且\(u\)是\(v\)的祖先的点对数量。

另外,我们定义一个新函数\(e(u,v)\)当\(u\)是\(v\)的祖先,且\(a_u=a_v\)时为\(1\),否则为\(0\)。显然\([u\)是\(v\)的祖先\(]\)等价于\(g(u,v)+h(u,v)+e(u,v)\)。那么化一下原式:

\[F(A,B)=C(|A|,2)+\sum_{v\in A,u\in A,v\not=u}g(v,u)+\sum_{v\in B,u\in B,v\not = u} h(v,u)+\sum_{v\in A,u\in B}g(v,u)+h(v,u)+e(v,u)
\]

把\(g\)和\(h\)合并到前面去,于是\(g\)和\(h\)的一半部分变成全集了:

\[F(A,B)=C(|A|,2)+\sum_{v\in A}g(v,u)+\sum_{u\in B} h(v,u)+\sum_{v\in A,u\in B}e(v,u)
\]

然后还有一个\(e\)比较烦人,注意到若\(v\)是\(u\)的祖先,且\(v\in B,u\in A\),如果交换\(v\)和\(u\),\(g\)部分会变更优,\(h\)部分会变更优,\(e\)部分也会变更优,当然会优先选择祖先……所以当一个点被加入\(A\)中时,他的祖先里和它权值一样的一定早就全都被加入到里面去了。所以\(e\)可以很轻松地计算,此时每个点加入A中带来的权值已经和其他元素毫不相干了,只需要用树状数值帮助预处理一下即可。

\(Code:\)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 500005
#define M 1000005
#define ll long long
ll ans[N];
int n, m, A[N], tre[N], sum[N];
int tar[M], nex[M], fir[N], cnt, tim;
int fat[N], dep[N], dfn[N], out[N], val[N], idx[N];
void Read(int &p)
{
p = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar());
for (; c >= '0' && c <= '9'; c = getchar())p = p * 10 + c - '0';
}
void Update(int x, int v)
{
for (int i = x; i <= N - 5; i += (i & -i))
tre[i] += v;
}
int Getsum(int x)
{
int ans = 0;
for (int i = x; i; i -= (i & -i))
ans += tre[i];
return ans;
}
void Add(int u, int v)
{
++cnt;
tar[cnt] = v;
nex[cnt] = fir[u];
fir[u] = cnt;
}
void Dfs(int r)
{
dfn[r] = ++tim;
val[r] = dep[r] - Getsum(A[r]);
Update(A[r], 1);
for (int i = fir[r]; i; i = nex[i])
{
int v = tar[i];
if (v != fat[r])
{
fat[v] = r;
dep[v] = dep[r] + 1;
Dfs(v);
}
}
Update(A[r], -1);
out[r] = tim;
};
bool cmp(int a, int b){return A[a] > A[b];}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
Read(A[i]), idx[i] = i;
for (int i = 1; i < n; i++)
{
int u, v;
Read(u), Read(v);
Add(u, v), Add(v, u);
}
Dfs(1);
sort(idx + 1, idx + n + 1, cmp);
for (int i = 1; i <= n; )
{
int x = i;
while (x <= n && A[idx[i]] == A[idx[x]])
x++;
for (int k = i; k < x; k++)
sum[idx[k]] = Getsum(out[idx[k]]) - Getsum(dfn[idx[k]] - 1);
for (int k = i; k < x; k++)
Update(dfn[idx[k]], 1);
i = x;
}
for (int i = 1; i <= n; i++)
val[i] -= sum[i], ans[0] += sum[i];
sort(val + 1, val + n + 1);
for (int i = 1; i <= n; i++)
ans[i] = ans[i - 1] + val[i] + i - 1;
for (; m--; )
{
int x;
Read(x);
printf("%lld\n", ans[x]);
}
}

「模拟赛20191019」C 推式子+贪心+树状数组的更多相关文章

  1. 「模拟赛20191019」B 容斥原理+DP计数

    题目描述 将\(n\times n\)的网格黑白染色,使得不存在任意一行.任意一列.任意一条大对角线的所有格子同色,求方案数对\(998244353\)取模的结果. 输入 一行一个整数\(n\). 输 ...

  2. 「模拟赛20191019」A 简单DP

    题目描述 给一个\(n\times m\)的网格,每个格子上有一个小写字母. 对于所有从左上角\((1,1)\)到右下角\((n,m)\)只向下或向右走的路径构成的集合,判断是否存在两条走法不同的路径 ...

  3. 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组

    题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...

  4. 「模拟赛20180307」三元组 exclaim 枚举+树状数组

    题目描述 给定 \(n,k\) ,求有多少个三元组 \((a,b,c)\) 满足 \(1≤a≤b≤c≤n\)且\(a + b^2 ≡ c^3\ (mod\ k)\). 输入 多组数据,第一行数据组数\ ...

  5. [CSP-S模拟测试]:斯诺(snow)(数学+前缀和+树状数组)

    题目传送门(内部题37) 输入格式 第一行一个整数$n$,表示区间的长度. 第二行一个长度为$n$的只包含$0,1,2$的字符串,表示给出的序列. 输出格式 一行一个整数,表示革命的区间的数量. 样例 ...

  6. 2019ICPC 上海网络赛 L. Digit sum(二维树状数组+区间求和)

    https://nanti.jisuanke.com/t/41422 题目大意: 给出n和b,求1到n,各数在b进制下各位数之和的总和. 直接暴力模拟,TLE.. 没想到是要打表...还是太菜了. # ...

  7. 「模拟赛20190327」 第二题 DP+决策单调性优化

    题目描述 小火车虽然很穷,但是他还是得送礼物给妹子,所以他前往了二次元寻找不需要钱的礼物. 小火车准备玩玩二次元的游戏,游戏当然是在一个二维网格中展开的,网格大小是\(n\times m\)的,某些格 ...

  8. 「模拟赛20181025」御风剑术 博弈论+DP简单优化

    题目描述 Yasuo 和Riven对一排\(n\)个假人开始练习.斩杀第\(i\)个假人会得到\(c_i\)个精粹.双方轮流出招,他们在练习中互相学习,所以他们的剑术越来越强.基于对方上一次斩杀的假人 ...

  9. 「模拟赛20180406」膜树 prufer编码+概率

    题目描述 给定一个完全图,保证\(w_{u,v}=w_{v,u}\)且\(w_{u,u}=0\),等概率选取一个随机生成树,对于每一对\((u,v)\),求\(dis(u,v)\)的期望值对\(998 ...

随机推荐

  1. Go语言在国产CPU平台上应用前景的探索与思考

    http://www.chinaaet.com/article/3000087559 0 引言 CPU是电子产品的核心,代表着信息产业的发展水平.CPU发展至今已经有四十多年的历史了,实际就是Inte ...

  2. windows认证过程

    NTLM简介: NTLM使用在Windows NT和Windows 2000 Server(or later)工作组环境中(Kerberos用在域模式下).在AD域环境中,如果需要认证Windows ...

  3. 基于VS2017+ROS的ROSOnWindows开坑之旅

    前面尝试了很多算法之后,得先找个能用的环境跑起来试试,于是决定尝试下ROS环境,但是我一直没有尝试Windows版也是因为这个原因,坑太多了,不过现在找到了微软IoT移植的ROSOnWindows,并 ...

  4. 注册服务到etcd中

    如上存放一些服务的key到etcd中,商品有两个,主要是为了负载均衡的key func NewService() *Service { config := clientv3.Config{ Endpo ...

  5. WinDbg常用命令系列---.cordll (控制CLR调试)

    .cordll (控制CLR调试) 简介 .cordell命令控制托管代码调试和Microsoft.NET公共语言运行库(CLR). 使用形式 .cordll [Options] 参数 Options ...

  6. 处理kubernetes 一些比较难删除的资源

    kubernetes 提供了force 的命令在我们删除资源的时候,但是很多时候还是不可以的 一般删除资源的处理 命令 kubectl delete <resource> <reso ...

  7. java.lang.IllegalAccessException: void #####.MyBroadcastReceiver.() is not accessible from jav

    java.lang.IllegalAccessException: void #####.MyBroadcastReceiver.<init>() is not accessible fr ...

  8. CDH 6.0.1 版本 默认配置下 HUE | happybase 无法访问 Hbase 的问题

    第一个问题 HUE 无法直接连接到 HBase 在默认配置下 CDH 6.0.1 版本下的 HBase2.0 使用了默认配置 hbase.regionserver.thrift.compact = T ...

  9. Git命令相关

    特别说明 关于命令行中参数前面的-和--的区别 - 通常后面接参数的缩写 -- 通常后面接参数的全拼 eg: git status --short 等价于 git status -s 常用命令 创建版 ...

  10. 【大数据应用技术】作业十二|Hadoop综合大作业

    本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3339 前言 本次作业是在<爬虫大作业>的基础上进行的 ...