[十二省联考2019]D2T2春节十二响

时间:2022-08-12 04:31:41

嘟嘟嘟



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



首先有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

*/