嘟嘟嘟




这题真没想到这么简单……




首先有60分大礼:\(O(n ^ 2logn)\)贪心。(我也不知道为啥就是对的)

然后又送15分链:维护两个堆,每次去堆顶的最大值。




这时候得到75分已经很开心了,但其实离AC也就差一点点。

链的做法已经给了我们提示:合并两个堆。其实这就相当于二叉树。那多叉树呢?就合并多个堆呗!从子树向上递归的时候不断将子树启发式合并,复杂度就保证了。




代码真的很短

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, a[maxn];
struct Edge
{
int nxt, to;
}e[maxn];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
} priority_queue<int> q[maxn];
int siz[maxn], tp[maxn];
In int dfs(int now)
{
int id1 = now;
for(int i = head[now], v; ~i; i = e[i].nxt)
{
v = e[i].to;
int id2 = dfs(v);
if(q[id1].size() < q[id2].size()) swap(id1, id2);
int Siz = q[id2].size();
for(int j = 1; j <= Siz; ++j) tp[j] = q[id1].top(), q[id1].pop();
for(int j = 1; j <= Siz; ++j)
{
q[id1].push(max(tp[j], q[id2].top()));
q[id2].pop();
}
}
q[id1].push(a[now]);
return id1;
} int main()
{
Mem(head, -1);
n = read();
for(int i = 1; i <= n; ++i) a[i] = read();
for(int i = 2, x; i <= n; ++i) x = read(), addEdge(x, i);
int id = dfs(1);
ll ans = 0;
while(!q[id].empty()) ans += q[id].top(), q[id].pop();
write(ans), enter;
return 0;
}



这题我考场上写了75分,结果成绩一出只剩20分了,当时真的怀疑人生,因为我对自己的暴力有十足的信心。然后查代码的时候看到了触目惊心的一幕:
```
if(judge_line) {work1(); return 0;}
```
天知道我`judge_line()`后面的括号去哪了。
-Wall没给我报错,自己复查的时候也没发现,编译也能过,就这样白白没了55分。
考场代码全放上来吧
```c++
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
const int N = 18;
In ll read()
{
ll ans = 0;
char ch = getchar(), las = ' ';
while(!isdigit(ch)) las = ch, ch = getchar();
while(isdigit(ch)) ans = (ans = 10) write(x / 10);
putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
freopen("spring.in", "r", stdin);
freopen("spring.out", "w", stdout);
#endif
}

int n, a[maxn];

struct Edge

{

int nxt, to;

}e[maxn];

int head[maxn], ecnt = -1;

In void addEdge(int x, int y)

{

e[++ecnt] = (Edge){head[x], y};

head[x] = ecnt;

}

int fa[N + 2][maxn], dep[maxn], siz[maxn];

In void dfs(int now, int _f)

{

siz[now] = 1;

for(int i = 1; (1 << i) <= dep[now]; ++i)

fa[i][now] = fa[i - 1][fa[i - 1][now]];

for(int i = head[now], v; ~i; i = e[i].nxt)

{

if((v = e[i].to) == _f) continue;

dep[v] = dep[now] + 1, fa[0][v] = now;

dfs(v, now);

siz[now] += siz[v];

}

}

In int lca(int x, int y)

{

if(dep[x] < dep[y]) swap(x, y);

for(int i = N; i >= 0; --i)

if(dep[x] - (1 << i) >= dep[y]) x = fa[i][x];

if(x == y) return x;

for(int i = N; i >= 0; --i)

if(fa[i][x] ^ fa[i][y]) x = fa[i][x], y = fa[i][y];

return fa[0][x];

}

struct Node

{

int val, siz, id;

In bool operator < (const Node& oth)const

{

return val > oth.val || (val == oth.val && siz < oth.siz);

}

}t[maxn];

vector vec[maxn];

int cnt = 0;

ll ans = 0;

In void work0()

{

for(int i = 1; i <= n; ++i) t[i] = (Node){a[i], siz[i], i};

sort(t + 1, t + n + 1);

for(int i = 1; i <= n; ++i)

{

bool flg1 = 0;

for(int j = 1; j <= cnt && !flg1; ++j)

{

bool flg2 = 1;

for(int k = 0; k < (int)vec[j].size() && flg2; ++k)

{

int v = vec[j][k], z = lca(t[i].id, v);

if(z == v || z == t[i].id) flg2 = 0;

}

if(flg2) vec[j].push_back(t[i].id), flg1 = 1;

}

if(!flg1) vec[++cnt].push_back(t[i].id), ans += t[i].val;

}

write(ans), enter;

}

int du[maxn];

In bool judge_line()

{

for(int i = 1; i <= n; ++i) if(du[i] > 2) return 0;

return 1;

}

priority_queue q[3];

In void dfs1(int now, int _f, int pos)

{

q[pos].push(a[now]);

for(int i = head[now]; ~i; i = e[i].nxt)

dfs1(e[i].to, now, pos);

}

In void work1()

{

for(int i = head[1], j = 1; ~i; i = e[i].nxt, ++j)

dfs1(e[i].to, 1, j);

while(!q[1].empty() || !q[2].empty())

{

if(q[2].empty()) {ans += q[1].top(), q[1].pop(); continue;}

if(q[1].empty()) {ans += q[2].top(), q[2].pop(); continue;}

if(q[1].top() >= q[2].top()) ans += q[1].top();

else ans += q[2].top();

q[1].pop(), q[2].pop();

}

write(ans + a[1]), enter;

}

int main()

{

MYFILE();

Mem(head, -1);

n = read();

for(int i = 1; i <= n; ++i) a[i] = read();

for(int i = 2; i <= n; ++i)

{

int x = read();

addEdge(x, i);

++du[x], ++du[i];

}

if(judge_line) {work1(); return 0;}

dfs(1, 0);

if(n <= 2000) {work0(); return 0;}

work0();

return 0;

}

/*

8

1 5 2 3 4 1 4 2

1 2 1 3 4 5 7

*/

[十二省联考2019]D2T2春节十二响的更多相关文章

  1. 「洛谷5290」「LOJ3052」「十二省联考 2019」春节十二响【启发式合并】

    题目链接 [洛谷传送门] [LOJ传送门] 题目大意 给定一棵树,每次选取树上的一个点集,要求点集中的每个点不能是另一个点的祖先,选出点集的代价为点集中权值最大点的权值,问将所有点都选一遍的最小代价为 ...

  2. LOJ#3052. 「十二省联考 2019」春节十二响(启发式合并)

    题面 传送门 题解 先考虑一条链的情况,对于\(1\)号点来说,肯定是左子树中最大值和右子树中最大值一组,左子树中次大值和右子树中次大值一组--以此类推 那么如果不是一条链呢?我们把所有的链合并起来就 ...

  3. Solution -「十二省联考2019」春节十二响

    题目 题意简述   link.   给一棵 \(n\) 个结点的有根树,点带权.把点分为若干组,并要求同组内不存在任何祖先-后代关系.最小化每组内的最大点权之和. 数据规模   \(n\le2\tim ...

  4. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  5. P5290 [十二省联考2019]春节十二响

    题目地址:P5290 [十二省联考2019]春节十二响 骗分方法 如果你实在一点思路也没有,暴力都不会打,那么请考虑一下骗分. 方法一 输出所有 \(M\) 的和. 期望得分:0分. 实际还有5分 方 ...

  6. P5290 [十二省联考2019]春节十二响(堆+启发式合并)

    P5290 [十二省联考2019]春节十二响 从特殊到一般 我们先看链的情况. 我们把点$1$左右的两条子链分别扔入堆里 每次取出两个堆的最大值,把答案累加上更大的那个(另一堆为空则直接加上去). 那 ...

  7. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  8. [十二省联考2019]异或粽子——可持久化trie树+堆

    题目链接: [十二省联考2019]异或粽子 求前$k$大异或区间,可以发现$k$比较小,我们考虑找出每个区间. 为了快速得到一个区间的异或和,将原序列做前缀异或和. 对于每个点作为右端点时,我们维护出 ...

  9. 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)

    [BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...

随机推荐

  1. July 09th, 2018. Monday, Week 28th.

    Happiness is an inside job. 自内寻找,才能找到幸福. From William Arthur Ward. Nobody wants to suffer, and we al ...

  2. @Autowired注解警告Field injection is not recommended

    在使用spring框架中的依赖注入注解@Autowired时,idea报了一个警告 大部分被警告的代码都是不严谨的地方,所以我深入了解了一下. 被警告的代码如下: @Autowired UserDao ...

  3. 我眼中的 Nginx(一):Nginx 和位运算

    作者张超:又拍云系统开发高级工程师,负责又拍云 CDN 平台相关组件的更新及维护.Github ID: tokers,活跃于 OpenResty 社区和 Nginx 邮件列表等开源社区,专注于服务端技 ...

  4. libevent和libcurl实现http和https服务器 cJSON使用

    前言 libevent和libcurl都是功能强大的开源库:libevent主要实现服务器,包含了select.epoll等高并发的实现:libcurl实现了curl命令的API封装,主要作为客户端. ...

  5. 在vue项目中添加全局提示框

    1.写一个提示框组件:msg.vue (注明:这里用两个div的原因是成功和失败的提示不能用同一个div,因为他们可能紧接着出现,所以不能从始至终只有一个提示框在工作) 2.写一个调用此组建的js : ...

  6. 使用FsCheck编写Property-based测试

    使用FsCheck编写Property-based的测试 在编写基于Property-based的单元测试一文中,我们介绍了什么是Property-based测试.同时我们也总结了Property-b ...

  7. 用于ViEmu的重置为试用状态的Python脚本

    import winreg import shutil shutil.rmtree("C:\\Users\\Administrator\\AppData\\Local\\Identities ...

  8. java_方法引用

    什么是方法引用? 个人简述方法引用: 方法引用主要是针对已经有的方法来让目前的编程更加简洁 当我们想要使用一个接口的子类的时候,子类需要重写这个接口中的抽象方法, 被重写的这个方法参数列表固定,返回值 ...

  9. nginx负载均衡指令least_conn的真正含义

    负载均衡指令least_conn的含义,按照nginx文档的说法: Specifies that a group should use a load balancing method where a ...

  10. JavaScript中的十个难点,你有必要知道。

    1. 立即执行函数 立即执行函数,即Immediately Invoked Function Expression (IIFE),正如它的名字,就是创建函数的同时立即执行.它没有绑定任何事件,也无需等 ...