Loading [MathJax]/extensions/tex2jax.js

「杂题集」- 2019年9月25日

[POI2008]BLO

一眼可以了解到是一道割点题。对于不是割点的情况,那么被计算的点对一定包含此点本身,又因为有序,所以贡献就是\(2(n – 1)\)。如果是割点的话,就比较麻烦,分下面几个来算:

  • 此点延伸出去的点对。
  • 连通块之间的点对。
  • 本身就无法互通的点对。

第一个很好算,是\(2(n – 1)\)。第二个,在 Tarjan 枚举搜索子树的时候计算子树大小和全图补集的乘积(注意,这里会多计算一遍与点\(u\)的点对,所以我们第一个改成算\(n – 1\));第三个,算「当前整颗搜索树与图的补集大小」与「搜索树的大小」的乘积。

综合起来就是,对于点\(u\):

\[ ans_u = \sum_{k \in son(u)} (n – size(k)) \times size(k) + (n – 1) + (n – 1 – \sum_{k \in son(u)} size(k)) \times (1 + \sum_{k \in son(u)} size(k)) \]

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// BZ1123.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 100010, MAX_M = 500010;
struct edge
{
int to, nxt;
} edges[MAX_M << 1];
int head[MAX_N], current, n, m, dfn[MAX_N], low[MAX_N], ptot, siz[MAX_N], root;
ll ans[MAX_N];
bool cut[MAX_N];
void addpath(int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src];
head[src] = current++;
}
void tarjan(int u)
{
ll flag = 0, sum = 0;
dfn[u] = low[u] = ++ptot, siz[u] = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (dfn[edges[i].to] == 0)
{
tarjan(edges[i].to), low[u] = min(low[edges[i].to], low[u]);
siz[u] += siz[edges[i].to];
if (low[edges[i].to] >= dfn[u])
{
flag++;
ans[u] += 1LL * (n - siz[edges[i].to]) * siz[edges[i].to];
// sum accumulated from cut;
sum += siz[edges[i].to];
if (u != 1 || flag > 1)
cut[u] = true;
}
}
else
low[u] = min(dfn[edges[i].to], low[u]);
if (!cut[u])
ans[u] = 2LL * (n - 1);
else
ans[u] += 1LL * (n - sum - 1) * (sum + 1) + (n - 1);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
tarjan(1);
for (int i = 1; i <= n; i++)
printf("%lld\n", ans[i]);
return 0;
}
// BZ1123.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 100010, MAX_M = 500010; struct edge { int to, nxt; } edges[MAX_M << 1]; int head[MAX_N], current, n, m, dfn[MAX_N], low[MAX_N], ptot, siz[MAX_N], root; ll ans[MAX_N]; bool cut[MAX_N]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } void tarjan(int u) { ll flag = 0, sum = 0; dfn[u] = low[u] = ++ptot, siz[u] = 1; for (int i = head[u]; i != -1; i = edges[i].nxt) if (dfn[edges[i].to] == 0) { tarjan(edges[i].to), low[u] = min(low[edges[i].to], low[u]); siz[u] += siz[edges[i].to]; if (low[edges[i].to] >= dfn[u]) { flag++; ans[u] += 1LL * (n - siz[edges[i].to]) * siz[edges[i].to]; // sum accumulated from cut; sum += siz[edges[i].to]; if (u != 1 || flag > 1) cut[u] = true; } } else low[u] = min(dfn[edges[i].to], low[u]); if (!cut[u]) ans[u] = 2LL * (n - 1); else ans[u] += 1LL * (n - sum - 1) * (sum + 1) + (n - 1); } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &n, &m); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u); tarjan(1); for (int i = 1; i <= n; i++) printf("%lld\n", ans[i]); return 0; }
// BZ1123.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int MAX_N = 100010, MAX_M = 500010;

struct edge
{
    int to, nxt;
} edges[MAX_M << 1];

int head[MAX_N], current, n, m, dfn[MAX_N], low[MAX_N], ptot, siz[MAX_N], root;
ll ans[MAX_N];
bool cut[MAX_N];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void tarjan(int u)
{
    ll flag = 0, sum = 0;
    dfn[u] = low[u] = ++ptot, siz[u] = 1;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (dfn[edges[i].to] == 0)
        {
            tarjan(edges[i].to), low[u] = min(low[edges[i].to], low[u]);
            siz[u] += siz[edges[i].to];
            if (low[edges[i].to] >= dfn[u])
            {
                flag++;
                ans[u] += 1LL * (n - siz[edges[i].to]) * siz[edges[i].to];
                // sum accumulated from cut;
                sum += siz[edges[i].to];
                if (u != 1 || flag > 1)
                    cut[u] = true;
            }
        }
        else
            low[u] = min(dfn[edges[i].to], low[u]);
    if (!cut[u])
        ans[u] = 2LL * (n - 1);
    else
        ans[u] += 1LL * (n - sum - 1) * (sum + 1) + (n - 1);
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v; i <= m; i++)
        scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
    tarjan(1);
    for (int i = 1; i <= n; i++)
        printf("%lld\n", ans[i]);
    return 0;
}

Codeforces Round #588 (Div. 2)

D – Marcin and Training Camp

考虑两种情况:

  • 如果技能的 Code 相同,那么可以认为这两个合并了。这个用 map 维护就行。
  • 如果技能的 Code 不同,那么在\(O(n^2)\)枚举的时候,找到一个\(S_i \subseteq S_j\),进行标记即可。
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1230D.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 7070;
ll skills[MAX_N], val[MAX_N], n;
bool tag[MAX_N];
map<ll, int> cnt;
int main()
{
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &skills[i]), cnt[skills[i]]++;
for (int i = 1; i <= n; i++)
scanf("%lld", &val[i]);
ll ans = 0;
for (int i = 1; i <= n; i++)
// set it as origin;
if (cnt[skills[i]] > 1)
for (int j = 1; j <= n; j++)
if ((skills[i] & skills[j]) == skills[j])
tag[j] = true;
for (int i = 1; i <= n; i++)
if (tag[i])
ans += val[i];
printf("%lld", ans);
return 0;
}
// CF1230D.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 7070; ll skills[MAX_N], val[MAX_N], n; bool tag[MAX_N]; map<ll, int> cnt; int main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) scanf("%lld", &skills[i]), cnt[skills[i]]++; for (int i = 1; i <= n; i++) scanf("%lld", &val[i]); ll ans = 0; for (int i = 1; i <= n; i++) // set it as origin; if (cnt[skills[i]] > 1) for (int j = 1; j <= n; j++) if ((skills[i] & skills[j]) == skills[j]) tag[j] = true; for (int i = 1; i <= n; i++) if (tag[i]) ans += val[i]; printf("%lld", ans); return 0; }
// CF1230D.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 7070;

ll skills[MAX_N], val[MAX_N], n;
bool tag[MAX_N];
map<ll, int> cnt;

int main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &skills[i]), cnt[skills[i]]++;
    for (int i = 1; i <= n; i++)
        scanf("%lld", &val[i]);
    ll ans = 0;
    for (int i = 1; i <= n; i++)
        // set it as origin;
        if (cnt[skills[i]] > 1)
            for (int j = 1; j <= n; j++)
                if ((skills[i] & skills[j]) == skills[j])
                    tag[j] = true;
    for (int i = 1; i <= n; i++)
        if (tag[i])
            ans += val[i];
    printf("%lld", ans);
    return 0;
}

E – Kamil and Making a Stream

这道题太妙了!

考虑正常的暴力情况:\(O(n^2)\)条链,直接统计完事。但是,发现:一条链向下的\(gcd\)一定都是根部的一个因子,根据对\(\gcd\)复杂度的论证,可以知道最多只会存在\(\log\)级别的\(\gcd\)个数。知道这个性质之后,我们在 DFS 的时候可以把父亲的链的\(gcd\)拿出来进行合并,乘上出现次数就行了。这个做法真的太神仙了。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1230E.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 100100, mod = 1e9 + 7;
int head[MAX_N], current;
ll val[MAX_N], ans, n;
map<ll, ll> mps[MAX_N];
struct edge
{
int to, nxt;
} edges[MAX_N << 1];
void addpath(int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src];
head[src] = current++;
}
ll gcd(ll a, ll b)
{
if (a == 0 && b == 0)
return 0;
if (a == 0)
return b;
return b == 0 ? a : gcd(b, a % b);
}
void dfs(int u, int fa)
{
for (map<ll, ll>::iterator it = mps[fa].begin(); it != mps[fa].end(); it++)
mps[u][gcd(val[u], it->first)] += it->second;
mps[u][val[u]]++;
for (map<ll, ll>::iterator it = mps[u].begin(); it != mps[u].end(); it++)
ans = (1LL * ans + 1LL * it->second * it->first % mod) % mod;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].to != fa)
dfs(edges[i].to, u);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
scanf("%lld", &val[i]);
for (int i = 1, u, v; i <= n - 1; i++)
scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
dfs(1, 0), printf("%lld", ans);
return 0;
}
// CF1230E.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 100100, mod = 1e9 + 7; int head[MAX_N], current; ll val[MAX_N], ans, n; map<ll, ll> mps[MAX_N]; struct edge { int to, nxt; } edges[MAX_N << 1]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } ll gcd(ll a, ll b) { if (a == 0 && b == 0) return 0; if (a == 0) return b; return b == 0 ? a : gcd(b, a % b); } void dfs(int u, int fa) { for (map<ll, ll>::iterator it = mps[fa].begin(); it != mps[fa].end(); it++) mps[u][gcd(val[u], it->first)] += it->second; mps[u][val[u]]++; for (map<ll, ll>::iterator it = mps[u].begin(); it != mps[u].end(); it++) ans = (1LL * ans + 1LL * it->second * it->first % mod) % mod; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].to != fa) dfs(edges[i].to, u); } int main() { memset(head, -1, sizeof(head)); scanf("%lld", &n); for (int i = 1; i <= n; i++) scanf("%lld", &val[i]); for (int i = 1, u, v; i <= n - 1; i++) scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u); dfs(1, 0), printf("%lld", ans); return 0; }
// CF1230E.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 100100, mod = 1e9 + 7;

int head[MAX_N], current;
ll val[MAX_N], ans, n;
map<ll, ll> mps[MAX_N];

struct edge
{
    int to, nxt;
} edges[MAX_N << 1];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

ll gcd(ll a, ll b)
{
    if (a == 0 && b == 0)
        return 0;
    if (a == 0)
        return b;
    return b == 0 ? a : gcd(b, a % b);
}

void dfs(int u, int fa)
{
    for (map<ll, ll>::iterator it = mps[fa].begin(); it != mps[fa].end(); it++)
        mps[u][gcd(val[u], it->first)] += it->second;
    mps[u][val[u]]++;
    for (map<ll, ll>::iterator it = mps[u].begin(); it != mps[u].end(); it++)
        ans = (1LL * ans + 1LL * it->second * it->first % mod) % mod;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa)
            dfs(edges[i].to, u);
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &val[i]);
    for (int i = 1, u, v; i <= n - 1; i++)
        scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
    dfs(1, 0), printf("%lld", ans);
    return 0;
}

F – Konrad and Company Evaluation

题意翻译过来就是动态维护长度为三的链的个数。当然,给你的询问肯定会简化一点:所有的边的方向都取决于边两点动态点权的大小关系。官方题解用了一种非常日狗的方式证明了,这样的边比较少,所以可以直接暴力。真的是日狗。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1230F.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 1e5 + 200;
list<int> l2r[MAX_N];
list<int> r2l[MAX_N];
int n, indeg[MAX_N], outdeg[MAX_N], salaries[MAX_N], m, q;
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
if (u < v)
swap(u, v);
r2l[u].push_back(v), l2r[v].push_back(u);
outdeg[v]++, indeg[u]++;
}
for (int i = 1; i <= n; i++)
salaries[i] = i;
ll ans = 0;
for (int i = 1; i <= n; i++)
for (list<int>::iterator it = r2l[i].begin(); it != r2l[i].end(); it++)
ans += indeg[*it];
printf("%lld\n", ans);
scanf("%d", &q);
int days = 0;
while (q--)
{
int u;
days++, scanf("%d", &u), salaries[u] = n + days;
ll flip_num = 0;
for (list<int>::iterator it = l2r[u].begin(); it != l2r[u].end();)
// if there is a edge needs flipping;
if (salaries[u] > salaries[*it])
{
int id = *it;
flip_num++;
indeg[id]--;
ans -= outdeg[id] - indeg[id];
outdeg[id]++;
list<int>::iterator backup = it;
backup++, l2r[u].erase(it), it = backup;
l2r[id].push_back(u);
}
else
it++;
ans += 1LL * (outdeg[u] - flip_num) * (indeg[u] + flip_num) - (1LL * indeg[u] * outdeg[u]);
indeg[u] += flip_num, outdeg[u] -= flip_num;
printf("%lld\n", ans);
}
return 0;
}
// CF1230F.cpp #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 1e5 + 200; list<int> l2r[MAX_N]; list<int> r2l[MAX_N]; int n, indeg[MAX_N], outdeg[MAX_N], salaries[MAX_N], m, q; int main() { scanf("%d%d", &n, &m); for (int i = 1, u, v; i <= m; i++) { scanf("%d%d", &u, &v); if (u < v) swap(u, v); r2l[u].push_back(v), l2r[v].push_back(u); outdeg[v]++, indeg[u]++; } for (int i = 1; i <= n; i++) salaries[i] = i; ll ans = 0; for (int i = 1; i <= n; i++) for (list<int>::iterator it = r2l[i].begin(); it != r2l[i].end(); it++) ans += indeg[*it]; printf("%lld\n", ans); scanf("%d", &q); int days = 0; while (q--) { int u; days++, scanf("%d", &u), salaries[u] = n + days; ll flip_num = 0; for (list<int>::iterator it = l2r[u].begin(); it != l2r[u].end();) // if there is a edge needs flipping; if (salaries[u] > salaries[*it]) { int id = *it; flip_num++; indeg[id]--; ans -= outdeg[id] - indeg[id]; outdeg[id]++; list<int>::iterator backup = it; backup++, l2r[u].erase(it), it = backup; l2r[id].push_back(u); } else it++; ans += 1LL * (outdeg[u] - flip_num) * (indeg[u] + flip_num) - (1LL * indeg[u] * outdeg[u]); indeg[u] += flip_num, outdeg[u] -= flip_num; printf("%lld\n", ans); } return 0; }
// CF1230F.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 1e5 + 200;

list<int> l2r[MAX_N];
list<int> r2l[MAX_N];

int n, indeg[MAX_N], outdeg[MAX_N], salaries[MAX_N], m, q;

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v; i <= m; i++)
    {
        scanf("%d%d", &u, &v);
        if (u < v)
            swap(u, v);
        r2l[u].push_back(v), l2r[v].push_back(u);
        outdeg[v]++, indeg[u]++;
    }
    for (int i = 1; i <= n; i++)
        salaries[i] = i;
    ll ans = 0;
    for (int i = 1; i <= n; i++)
        for (list<int>::iterator it = r2l[i].begin(); it != r2l[i].end(); it++)
            ans += indeg[*it];
    printf("%lld\n", ans);
    scanf("%d", &q);
    int days = 0;
    while (q--)
    {
        int u;
        days++, scanf("%d", &u), salaries[u] = n + days;
        ll flip_num = 0;
        for (list<int>::iterator it = l2r[u].begin(); it != l2r[u].end();)
            // if there is a edge needs flipping;
            if (salaries[u] > salaries[*it])
            {
                int id = *it;
                flip_num++;
                indeg[id]--;
                ans -= outdeg[id] - indeg[id];
                outdeg[id]++;
                list<int>::iterator backup = it;
                backup++, l2r[u].erase(it), it = backup;
                l2r[id].push_back(u);
            }
            else
                it++;
        ans += 1LL * (outdeg[u] - flip_num) * (indeg[u] + flip_num) - (1LL * indeg[u] * outdeg[u]);
        indeg[u] += flip_num, outdeg[u] -= flip_num;
        printf("%lld\n", ans);
    }
    return 0;
}

线性时间建二叉树

一种方式是建笛卡尔树,但是我不会。另一种方式是「双端队列」:从后往前进行加边,且这个二叉树的中序遍历一定,所以合并的时候也要把序号的进行合并。可以看这道题:P1377 [TJOI2011]树的序。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P1377.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200;
int seq[MAX_N], pos[MAX_N], lft[MAX_N], rig[MAX_N], n, lson[MAX_N], rson[MAX_N];
void dfs(int u)
{
if (u == 0)
return;
printf("%d ", u);
dfs(lson[u]), dfs(rson[u]);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &seq[i]), pos[seq[i]] = i;
lft[i] = i - 1, rig[i] = i + 1;
}
for (int i = n; i >= 2; i--)
{
// connect to the prev or back one;
int l = lft[seq[i]], r = rig[seq[i]];
if (pos[l] > pos[r])
rson[l] = seq[i];
else
lson[r] = seq[i];
lft[r] = l, rig[l] = r;
}
dfs(seq[1]);
return 0;
}
// P1377.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200; int seq[MAX_N], pos[MAX_N], lft[MAX_N], rig[MAX_N], n, lson[MAX_N], rson[MAX_N]; void dfs(int u) { if (u == 0) return; printf("%d ", u); dfs(lson[u]), dfs(rson[u]); } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &seq[i]), pos[seq[i]] = i; lft[i] = i - 1, rig[i] = i + 1; } for (int i = n; i >= 2; i--) { // connect to the prev or back one; int l = lft[seq[i]], r = rig[seq[i]]; if (pos[l] > pos[r]) rson[l] = seq[i]; else lson[r] = seq[i]; lft[r] = l, rig[l] = r; } dfs(seq[1]); return 0; }
// P1377.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200;

int seq[MAX_N], pos[MAX_N], lft[MAX_N], rig[MAX_N], n, lson[MAX_N], rson[MAX_N];

void dfs(int u)
{
    if (u == 0)
        return;
    printf("%d ", u);
    dfs(lson[u]), dfs(rson[u]);
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &seq[i]), pos[seq[i]] = i;
        lft[i] = i - 1, rig[i] = i + 1;
    }
    for (int i = n; i >= 2; i--)
    {
        //  connect to the prev or back one;
        int l = lft[seq[i]], r = rig[seq[i]];
        if (pos[l] > pos[r])
            rson[l] = seq[i];
        else
            lson[r] = seq[i];
        lft[r] = l, rig[l] = r;
    }
    dfs(seq[1]);
    return 0;
}

出行预算

这道题也算是贪心的好题了。首先做好预处理,处理好\(n\)段的距离之类的东西。之后,我们一段一段来走:首先,我们要维护一个可以始终提供便宜油的节点,然后也需要知道之前在油箱里放了多少可供现在使用的油;知道这些之后,我们就可以贪心取,然后用线段树来维护油箱即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// B.cpp
#include <bits/stdc++.h>
#define pr pair<double, int>
using namespace std;
const int MAX_N = 500100;
int n;
double D, C, d0, nodes[MAX_N << 2], tag[MAX_N << 2], di[MAX_N], pi[MAX_N], segs[MAX_N];
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void pushdown(int p)
{
if (tag[p] != 0)
{
nodes[lson] += tag[p], nodes[rson] += tag[p];
tag[lson] += tag[p], tag[rson] += tag[p];
tag[p] = 0;
}
}
void pushup(int p)
{
nodes[p] = nodes[lson] + nodes[rson];
}
void update(int ql, int qr, int l, int r, int p, double val)
{
if (ql <= l && r <= qr)
return (void)(nodes[p] += val, tag[p] += val);
pushdown(p);
if (ql <= mid)
update(ql, qr, l, mid, lson, val);
if (mid < qr)
update(ql, qr, mid + 1, r, rson, val);
pushup(p);
}
double query(int ql, int qr, int l, int r, int p)
{
if (ql <= l && r <= qr)
return nodes[p];
double ret = 0;
if (ql <= mid)
ret = max(ret, query(ql, qr, l, mid, lson));
if (mid < qr)
ret = max(ret, query(ql, qr, mid + 1, r, rson));
return ret;
}
#undef lson
#undef rson
#undef mid
int main()
{
scanf("%d%lf%lf%lf", &n, &D, &C, &d0);
for (int i = 1; i <= n; i++)
scanf("%lf%lf", &di[i], &pi[i]);
for (int i = 1; i <= n - 1; i++)
segs[i] = di[i + 1] - di[i];
segs[n] = D - di[n];
priority_queue<pr> pq;
int lastpos = 0;
double ans = 0;
for (int i = 1; i <= n; i++)
{
pq.push(make_pair(-pi[i], i));
double need = segs[i] / d0;
while (need > 0)
{
if (pq.empty())
puts("Poor Congcong"), exit(0);
int pos = pq.top().second;
if (pos <= lastpos)
{
pq.pop();
continue;
}
double lft = C - query(pos, i, 1, n, 1);
if (lft <= 0)
{
pq.pop();
break;
}
if (need - lft <= 0)
{
ans += need * pi[pos];
update(pos, i, 1, n, 1, need);
need = 0;
}
else
{
ans += lft * pi[pos];
need -= lft, update(pos, i, 1, n, 1, lft);
lastpos = max(lastpos, pos);
pq.pop();
}
}
}
printf("%.2lf", ans);
return 0;
}
// B.cpp #include <bits/stdc++.h> #define pr pair<double, int> using namespace std; const int MAX_N = 500100; int n; double D, C, d0, nodes[MAX_N << 2], tag[MAX_N << 2], di[MAX_N], pi[MAX_N], segs[MAX_N]; #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) void pushdown(int p) { if (tag[p] != 0) { nodes[lson] += tag[p], nodes[rson] += tag[p]; tag[lson] += tag[p], tag[rson] += tag[p]; tag[p] = 0; } } void pushup(int p) { nodes[p] = nodes[lson] + nodes[rson]; } void update(int ql, int qr, int l, int r, int p, double val) { if (ql <= l && r <= qr) return (void)(nodes[p] += val, tag[p] += val); pushdown(p); if (ql <= mid) update(ql, qr, l, mid, lson, val); if (mid < qr) update(ql, qr, mid + 1, r, rson, val); pushup(p); } double query(int ql, int qr, int l, int r, int p) { if (ql <= l && r <= qr) return nodes[p]; double ret = 0; if (ql <= mid) ret = max(ret, query(ql, qr, l, mid, lson)); if (mid < qr) ret = max(ret, query(ql, qr, mid + 1, r, rson)); return ret; } #undef lson #undef rson #undef mid int main() { scanf("%d%lf%lf%lf", &n, &D, &C, &d0); for (int i = 1; i <= n; i++) scanf("%lf%lf", &di[i], &pi[i]); for (int i = 1; i <= n - 1; i++) segs[i] = di[i + 1] - di[i]; segs[n] = D - di[n]; priority_queue<pr> pq; int lastpos = 0; double ans = 0; for (int i = 1; i <= n; i++) { pq.push(make_pair(-pi[i], i)); double need = segs[i] / d0; while (need > 0) { if (pq.empty()) puts("Poor Congcong"), exit(0); int pos = pq.top().second; if (pos <= lastpos) { pq.pop(); continue; } double lft = C - query(pos, i, 1, n, 1); if (lft <= 0) { pq.pop(); break; } if (need - lft <= 0) { ans += need * pi[pos]; update(pos, i, 1, n, 1, need); need = 0; } else { ans += lft * pi[pos]; need -= lft, update(pos, i, 1, n, 1, lft); lastpos = max(lastpos, pos); pq.pop(); } } } printf("%.2lf", ans); return 0; }
// B.cpp
#include <bits/stdc++.h>
#define pr pair<double, int>
using namespace std;

const int MAX_N = 500100;

int n;
double D, C, d0, nodes[MAX_N << 2], tag[MAX_N << 2], di[MAX_N], pi[MAX_N], segs[MAX_N];

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

void pushdown(int p)
{
    if (tag[p] != 0)
    {
        nodes[lson] += tag[p], nodes[rson] += tag[p];
        tag[lson] += tag[p], tag[rson] += tag[p];
        tag[p] = 0;
    }
}

void pushup(int p)
{
    nodes[p] = nodes[lson] + nodes[rson];
}

void update(int ql, int qr, int l, int r, int p, double val)
{
    if (ql <= l && r <= qr)
        return (void)(nodes[p] += val, tag[p] += val);
    pushdown(p);
    if (ql <= mid)
        update(ql, qr, l, mid, lson, val);
    if (mid < qr)
        update(ql, qr, mid + 1, r, rson, val);
    pushup(p);
}

double query(int ql, int qr, int l, int r, int p)
{
    if (ql <= l && r <= qr)
        return nodes[p];
    double ret = 0;
    if (ql <= mid)
        ret = max(ret, query(ql, qr, l, mid, lson));
    if (mid < qr)
        ret = max(ret, query(ql, qr, mid + 1, r, rson));
    return ret;
}

#undef lson
#undef rson
#undef mid

int main()
{
    scanf("%d%lf%lf%lf", &n, &D, &C, &d0);
    for (int i = 1; i <= n; i++)
        scanf("%lf%lf", &di[i], &pi[i]);
    for (int i = 1; i <= n - 1; i++)
        segs[i] = di[i + 1] - di[i];
    segs[n] = D - di[n];
    priority_queue<pr> pq;
    int lastpos = 0;
    double ans = 0;
    for (int i = 1; i <= n; i++)
    {
        pq.push(make_pair(-pi[i], i));
        double need = segs[i] / d0;
        while (need > 0)
        {
            if (pq.empty())
                puts("Poor Congcong"), exit(0);
            int pos = pq.top().second;
            if (pos <= lastpos)
            {
                pq.pop();
                continue;
            }
            double lft = C - query(pos, i, 1, n, 1);
            if (lft <= 0)
            {
                pq.pop();
                break;
            }
            if (need - lft <= 0)
            {
                ans += need * pi[pos];
                update(pos, i, 1, n, 1, need);
                need = 0;
            }
            else
            {
                ans += lft * pi[pos];
                need -= lft, update(pos, i, 1, n, 1, lft);
                lastpos = max(lastpos, pos);
                pq.pop();
            }
        }
    }
    printf("%.2lf", ans);
    return 0;
}

收作业

考场上切掉了。首先,最短路一定是不降路径;其次,不需要考虑具体的转移方式,所以可以直接找域内的点进行转移。二位偏序搞掉(第一次在考场上写这种玩意)。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// homework.cpp
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int X = 0, w = 0;
char ch = 0;
while (!isdigit(ch))
{
w |= ch == '-';
ch = getchar();
}
while (isdigit(ch))
X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
const int MAX_N = 2e5 + 200;
struct point
{
int x, y, val, id;
bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); }
} pts[MAX_N];
int n, m, k, dp[MAX_N], tree[MAX_N << 1], upper;
vector<int> mpx, mpy;
inline int lowbit(int x) { return x & -x; }
void update(int x, int d)
{
if (x == 0)
return;
for (; x <= upper; x += lowbit(x))
tree[x] = max(tree[x], d);
}
int query(int x)
{
int ans = 0;
for (; x > 0; x -= lowbit(x))
ans = max(tree[x], ans);
return ans;
}
int main()
{
freopen("homework.in", "r", stdin);
freopen("homework.out", "w", stdout);
n = read(), m = read(), k = read();
for (int i = 1; i <= k; i++)
{
pts[i].x = read(), pts[i].y = read(), pts[i].val = read(), pts[i].id = i;
mpx.push_back(pts[i].x), mpy.push_back(pts[i].y);
}
pts[k + 1] = point{n - 1, m - 1, 0, k + 1}, k++;
mpx.push_back(n - 1), mpy.push_back(m - 1);
sort(mpx.begin(), mpx.end()), sort(mpy.begin(), mpy.end());
mpx.erase(unique(mpx.begin(), mpx.end()), mpx.end());
mpy.erase(unique(mpy.begin(), mpy.end()), mpy.end());
upper = mpy.size();
for (int i = 1; i <= k; i++)
{
pts[i].x = lower_bound(mpx.begin(), mpx.end(), pts[i].x) - mpx.begin() + 1;
pts[i].y = lower_bound(mpy.begin(), mpy.end(), pts[i].y) - mpy.begin() + 1;
}
sort(pts + 1, pts + 1 + k);
for (int i = 1; i <= k; i++)
{
int ans = query(pts[i].y);
dp[pts[i].id] = ans + pts[i].val;
update(pts[i].y, dp[pts[i].id]);
}
printf("%d", dp[k]);
return 0;
}
// homework.cpp #include <bits/stdc++.h> using namespace std; inline int read() { int X = 0, w = 0; char ch = 0; while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); } while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar(); return w ? -X : X; } const int MAX_N = 2e5 + 200; struct point { int x, y, val, id; bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); } } pts[MAX_N]; int n, m, k, dp[MAX_N], tree[MAX_N << 1], upper; vector<int> mpx, mpy; inline int lowbit(int x) { return x & -x; } void update(int x, int d) { if (x == 0) return; for (; x <= upper; x += lowbit(x)) tree[x] = max(tree[x], d); } int query(int x) { int ans = 0; for (; x > 0; x -= lowbit(x)) ans = max(tree[x], ans); return ans; } int main() { freopen("homework.in", "r", stdin); freopen("homework.out", "w", stdout); n = read(), m = read(), k = read(); for (int i = 1; i <= k; i++) { pts[i].x = read(), pts[i].y = read(), pts[i].val = read(), pts[i].id = i; mpx.push_back(pts[i].x), mpy.push_back(pts[i].y); } pts[k + 1] = point{n - 1, m - 1, 0, k + 1}, k++; mpx.push_back(n - 1), mpy.push_back(m - 1); sort(mpx.begin(), mpx.end()), sort(mpy.begin(), mpy.end()); mpx.erase(unique(mpx.begin(), mpx.end()), mpx.end()); mpy.erase(unique(mpy.begin(), mpy.end()), mpy.end()); upper = mpy.size(); for (int i = 1; i <= k; i++) { pts[i].x = lower_bound(mpx.begin(), mpx.end(), pts[i].x) - mpx.begin() + 1; pts[i].y = lower_bound(mpy.begin(), mpy.end(), pts[i].y) - mpy.begin() + 1; } sort(pts + 1, pts + 1 + k); for (int i = 1; i <= k; i++) { int ans = query(pts[i].y); dp[pts[i].id] = ans + pts[i].val; update(pts[i].y, dp[pts[i].id]); } printf("%d", dp[k]); return 0; }
// homework.cpp
#include <bits/stdc++.h>

using namespace std;

inline int read()
{
    int X = 0, w = 0;
    char ch = 0;
    while (!isdigit(ch))
    {
        w |= ch == '-';
        ch = getchar();
    }
    while (isdigit(ch))
        X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}

const int MAX_N = 2e5 + 200;

struct point
{
    int x, y, val, id;
    bool operator<(const point &pt) const { return x < pt.x || (x == pt.x && y < pt.y); }
} pts[MAX_N];

int n, m, k, dp[MAX_N], tree[MAX_N << 1], upper;
vector<int> mpx, mpy;

inline int lowbit(int x) { return x & -x; }

void update(int x, int d)
{
    if (x == 0)
        return;
    for (; x <= upper; x += lowbit(x))
        tree[x] = max(tree[x], d);
}

int query(int x)
{
    int ans = 0;
    for (; x > 0; x -= lowbit(x))
        ans = max(tree[x], ans);
    return ans;
}

int main()
{
    freopen("homework.in", "r", stdin);
    freopen("homework.out", "w", stdout);
    n = read(), m = read(), k = read();
    for (int i = 1; i <= k; i++)
    {
        pts[i].x = read(), pts[i].y = read(), pts[i].val = read(), pts[i].id = i;
        mpx.push_back(pts[i].x), mpy.push_back(pts[i].y);
    }
    pts[k + 1] = point{n - 1, m - 1, 0, k + 1}, k++;
    mpx.push_back(n - 1), mpy.push_back(m - 1);
    sort(mpx.begin(), mpx.end()), sort(mpy.begin(), mpy.end());
    mpx.erase(unique(mpx.begin(), mpx.end()), mpx.end());
    mpy.erase(unique(mpy.begin(), mpy.end()), mpy.end());
    upper = mpy.size();
    for (int i = 1; i <= k; i++)
    {
        pts[i].x = lower_bound(mpx.begin(), mpx.end(), pts[i].x) - mpx.begin() + 1;
        pts[i].y = lower_bound(mpy.begin(), mpy.end(), pts[i].y) - mpy.begin() + 1;
    }
    sort(pts + 1, pts + 1 + k);
    for (int i = 1; i <= k; i++)
    {
        int ans = query(pts[i].y);
        dp[pts[i].id] = ans + pts[i].val;
        update(pts[i].y, dp[pts[i].id]);
    }
    printf("%d", dp[k]);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *