2018冬令营模拟测试赛(十九)

Posted xjr_01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018冬令营模拟测试赛(十九)相关的知识,希望对你有一定的参考价值。

2018冬令营模拟测试赛(十九)

[Problem A]小Y

试题描述

QAQ

TAT

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

目前未知。

这题目前就能做到 \\(O(n \\sqrt{M} \\log n)\\),其中 \\(M\\) 是逆序对数,然而会被卡 T;当然这题暴力可以拿到和左边那个算法一样的分数,只要暴力加一个剪枝:当左区间最大值小于右区间最小值时就直接输出阶乘。

// 略(不要打我 TAT)

[Problem B]暗牧

试题描述

T_T

QwQ

ToT

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

这题要用到的节点不多,自然想到构建虚树。把所有边和询问所提到的点都作为关键点,每棵树分别处理,这样能把点数压成 \\(4(m+q)\\),边数也是这个级别的,最后跑 \\(q\\) 遍最短路就好了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
#include <cassert>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
 
int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == \'-\') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - \'0\'; c = getchar(); }
    return x * f;
}
 
#define maxtrn 300010
#define maxlog 19
#define maxom 100010
#define maxn 400050
#define maxm 1000090
#define ool (1ll << 60)
#define LL long long
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
 
int ToT;
struct Graph {
    int m, head[maxn], nxt[maxm], to[maxm], dist[maxm];
 
    void AddEdge(int a, int b) {
        to[++m] = b; nxt[m] = head[a]; head[a] = m;
        swap(a, b);
        to[++m] = b; nxt[m] = head[a]; head[a] = m;
        return ;
    }
     
    void AddEdge(int a, int b, int c) {
        assert(a >= 0 && b >= 0);
        // printf("edge %d %d, %d\\n", a, b, c);
        to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
        swap(a, b);
        to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
        return ;
    }
} tr, G;
 
int fa[maxtrn][maxlog], dep[maxtrn], dfn[maxtrn], clo;
void build(int u) {
    dfn[u] = ++clo;
    rep(i, 1, maxlog - 1) fa[u][i] = fa[fa[u][i-1]][i-1];
    for(int e = tr.head[u]; e; e = tr.nxt[e]) if(tr.to[e] != fa[u][0]) {
        fa[tr.to[e]][0] = u;
        dep[tr.to[e]] = dep[u] + 1;
        build(tr.to[e]);
    }
    return ;
}
int lca(int a, int b) {
    if(dep[a] < dep[b]) swap(a, b);
    dwn(i, maxlog - 1, 0) if(dep[a] - dep[b] >= (1 << i)) a = fa[a][i];
    dwn(i, maxlog - 1, 0) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    return a == b ? a : fa[b][0];
}
 
struct Edge {
    int p1, u1, p2, u2;
    Edge() {}
    Edge(int _1, int _2, int _3, int _4): p1(_1), u1(_2), p2(_3), u2(_4) {}
} es[maxom], qs[15];
int num[(maxom<<1)+20], cntn, gnode[maxtrn<<1];
vector <int> vnode[(maxom<<1)+20];
const bool cmp(const int& a, const int& b) {
    return dfn[a] < dfn[b];
}
const bool cmpequ(const int& a, const int& b) {
    return dfn[a] == dfn[b];
}
 
const int HMOD = 1000037;
struct Hash {
    int tot, head[HMOD], nxt[maxn], id[maxn];
    pii key[maxn];
    void Insert(pii a, int v) {
        // printf("insert: pair(%d, %d) %d\\n", a.x, a.y, v);
        int u = (a.x * 233 + a.y) % HMOD;
        nxt[++tot] = head[u]; id[tot] = v; key[tot] = a; head[u] = tot;
        return ;
    }
    int Find(pii a) {
        int u = (a.x * 233 + a.y) % HMOD;
        for(int e = head[u]; e; e = nxt[e]) if(key[e].x == a.x && key[e].y == a.y) return id[e];
        return -1;
    }
} hh;
 
struct Node {
    int u; LL d;
    Node() {}
    Node(int _, LL __): u(_), d(__) {}
    bool operator < (const Node& t) const { return d > t.d; }
};
LL d[maxn];
bool vis[maxn];
priority_queue <Node> Q;
LL ShortPath(int s, int t) {
    rep(i, 1, ToT) d[i] = ool;
    memset(vis, 0, sizeof(vis));
    d[s] = 0;
    Q.push(Node(s, 0));
    while(!Q.empty()) {
        int u = Q.top().u; Q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int e = G.head[u]; e; e = G.nxt[e]) if(d[G.to[e]] > d[u] + G.dist[e]) {
            d[G.to[e]] = d[u] + G.dist[e];
            if(!vis[G.to[e]]) Q.push(Node(G.to[e], d[G.to[e]]));
        }
    }
    return d[t];
}
 
int main() {
    int n = read(), m = read(), q = read();
    rep(i, 1, n - 1) {
        int a = read(), b = read();
        tr.AddEdge(a, b);
    }
    build(1);
    rep(i, 1, m) {
        int p1 = read(), u1 = read(), p2 = read(), u2 = read();
        es[i] = Edge(p1, u1, p2, u2);
        num[++cntn] = u1; num[++cntn] = u2;
    }
    rep(i, 1, q) {
        int p1 = read(), u1 = read(), p2 = read(), u2 = read();
        qs[i] = Edge(p1, u1, p2, u2);
        num[++cntn] = u1; num[++cntn] = u2;
    }
    sort(num + 1, num + cntn + 1);
    cntn = unique(num + 1, num + cntn + 1) - num - 1;
     
    rep(i, 1, m) {
        es[i].u1 = lower_bound(num + 1, num + cntn + 1, es[i].u1) - num;
        es[i].u2 = lower_bound(num + 1, num + cntn + 1, es[i].u2) - num;
        // printf("%d <- %d; %d <- %d\\n", es[i].u1, es[i].p1, es[i].u2, es[i].p2);
        vnode[es[i].u1].push_back(es[i].p1);
        vnode[es[i].u2].push_back(es[i].p2);
    }
    rep(i, 1, q) {
        qs[i].u1 = lower_bound(num + 1, num + cntn + 1, qs[i].u1) - num;
        qs[i].u2 = lower_bound(num + 1, num + cntn + 1, qs[i].u2) - num;
        // printf("%d <- %d; %d <- %d\\n", qs[i].u1, qs[i].p1, qs[i].u2, qs[i].p2);
        vnode[qs[i].u1].push_back(qs[i].p1);
        vnode[qs[i].u2].push_back(qs[i].p2);
    }
    rep(i, 1, cntn) {
        sort(vnode[i].begin(), vnode[i].end(), cmp);
        vector <int> :: iterator it = unique(vnode[i].begin(), vnode[i].end(), cmpequ);
        vnode[i].erase(it, vnode[i].end());
         
        // printf("tree %d:", i); for(auto j : vnode[i]) printf(" %d", j); putchar(\'\\n\');
         
        int cntg = 0;
        rep(j, 0, vnode[i].size() - 1) {
            gnode[++cntg] = vnode[i][j];
            if(j < vnode[i].size() - 1) gnode[++cntg] = lca(vnode[i][j], vnode[i][j+1]);
        }
        sort(gnode + 1, gnode + cntg + 1, cmp);
        cntg = unique(gnode + 1, gnode + cntg + 1, cmpequ) - gnode - 1;
        rep(j, 1, cntg) hh.Insert(mp(i, gnode[j]), ++ToT);
        rep(j, 1, cntg)
            if(j > 1) {
                int a = lca(gnode[j-1], gnode[j]);
                G.AddEdge(hh.Find(mp(i, a)), hh.Find(mp(i, gnode[j])), dep[gnode[j]] - dep[a]);
            }
    }
    rep(i, 1, m) G.AddEdge(hh.Find(mp(es[i].u1, es[i].p1)), hh.Find(mp(es[i].u2, es[i].p2)), 1);
     
    rep(i, 1, q) {
        int p1 = qs[i].p1, u1 = qs[i].u1, p2 = qs[i].p2, u2 = qs[i].u2;
        LL ans = ShortPath(hh.Find(mp(u1, p1)), hh.Find(mp(u2, p2)));
        if(ans < ool) printf("%lld\\n", ans); else puts("impossible");
    }
     
    return 0;
}

[Problem C]大根

试题描述

TwT

Q_Q

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

这题可以转化成生成 \\(k\\) 个不相交区间,要求每个元区间都包含至少一个生成的区间,且生成的区间至少被一个原区间包含。

于是变成两种贪心取最优:

  • 将包含别的区间的区间放到集合 \\(B\\) 中,否则放到集合 \\(A\\) 中,然后枚举 \\(A\\) 中分 \\(k_1\\) 类,那么 \\(B\\) 中选择 \\(k - k_1\\) 个。\\(B\\) 中选的一定是单个区间。这样能保证合法(想想为什么)。

  • 按长度排序取前 \\(k-1\\) 个,然后剩下的所有分一类。(这就是在上面有区间集合的交集为 \\(0\\) 的时候这种贪心才会起作用)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
 
int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == \'-\') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - \'0\'; c = getchar(); }
    return x * f;
}
 
#define maxn 1000010
#define LL long long
 
struct Line {
    int l, r;
    Line() {}
    Line(int _, int __): l(_), r(__) {}
    bool operator == (const Line& t) const { return l == t.l && r == t.r; }
    bool operator < (const Line& t) const { return r != t.r ? r < t.r : l > t.l; }
    Line operator * (const Line& t) const { return Line(max(l, t.l), min(r, t.r)); }
    Line operator *= (const Line& t) { *this = *this * t; return *this; }
} ls[maxn], getl[maxn], bigl[maxn];
int n, K, cntg, cntb, val[maxn];
 
bool cmplen(Line a, Line b) { return a.r - a.l > b.r - b.l; }
 
int main() {
    n = read(); K = read();
    rep(i, 1, n) {
        int l = read(), r = read();
        ls[i] = Line(l, r);
    }
     
    sort(ls + 1, ls + n + 1);
    for(int i = 1; i <= n; ) {
        getl[++cntg] = ls[i++];
        while(i <= n && ls[i] * ls[i-1] == ls[i-1]) bigl[++cntb] = ls[i++];
    }
    sort(bigl + 1, bigl + cntb + 1, cmplen);
    sort(getl + 1, getl + cntg + 1);
    LL sum = 0, ans = 0;
    rep(i, 1, cntg) sum += getl[i].r - getl[i].l;
    rep(i, 1, cntg - 1) val[i] = getl[i+1].r - getl[i].l;
    sort(val + 1, val + cntg), reverse(val + 1, val + cntg);
    dwn(i, cntg - 1, K) sum -= val[i];
    rep(i, cntg + 1, K) sum += bigl[i-cntg].r - bigl[i-cntg].l;
    int cg, cb;
    if(cntg <= K) cg = cntg, cb = K - cntg;
    else cg = K, cb = 0;
    ans = max(ans, sum);
    for(; cg > 1;) {
        sum -= val[--cg];
        cb++; sum += bigl[cb].r - bigl[cb].l;
        ans = max(ans, sum);
    }
     
    sum = 0;
    sort(ls + 1, ls + n + 1, cmplen);
    rep(i, 1, K - 1) sum += ls[i].r - ls[i].l;
     
    printf("%lld\\n", max(ans, sum));
     
    return 0;
}

以上是关于2018冬令营模拟测试赛(十九)的主要内容,如果未能解决你的问题,请参考以下文章

2018冬令营模拟测试赛(十四)

2018冬令营模拟测试赛(十七)

2018冬令营模拟测试赛

2018冬令营模拟测试赛(十八)

2018冬令营模拟测试赛

2018.8.6 Noip2018模拟测试赛(十九)