[Codeforces Round #700(Div.1)] 1479D – Odd Mineral Resource

这个题出得确实挺好的(
(我怎么感觉我没用到题目的一些性质)
题目链接

恰好可以学习一个知识叫做树上莫队,也就是求出这棵树的欧拉序然后在序上做莫队。注意 lca 不是 u 或 v 的话还需要特判一下。

然后就来到这个题:树上不带修,完全可以做莫队。
由于 n 和 q 都很大,所以莫队修改的时候就只有 $\mathcal{O}(1)$ 来搞,之前写了一发 $\mathcal{O}(\log n)$ 的完美 T 掉了(

设 cnt(c) 表示当前颜色 c 的出现次数,把颜色 1~n 分块来搞,处理每一块里面 cnt 为奇数的颜色个数,这样找到某一块个数大于 0 时再在这一块里面遍历一下就可以找到合法的颜色。

这样,询问的时候复杂度是 $\mathcal{O}(n(B+\frac{n}{B}))$($B$ 是块大小),莫队的复杂度也是 $\mathcal{O}(n(B+\frac{n}{B}))$,那么总的时间复杂度也就是 $\mathcal{O}(n(B+\frac{n}{B}))$.

不过这个题也可以用 bitset 来乱搞。用一个 bitset 维护每一个颜色出现次数的奇偶性,不过 stl 里面的 bitset 不支持提取一段区间的操作,这个时候可以先预存 100 个 bitset,其中 1 是连续的一大段,比如 0000011, 0001100 这种。然后就是一坨一坨的这些 bitset 或起来,首尾单独处理一下,再和原 bitset 与一次,就可以提取相应段了,用 _Find_first() 函数可以较高效率求得第一个 1 的位置。这样,时间复杂度就是 $\mathcal{O}(\frac{nq}{w})$,勉强还是能跑过的。

不过官方题解做法更加神奇就是了……

#include <bits/stdc++.h>
#define ll long long
#define ls id << 1
#define rs id << 1 | 1
#define mem(array, value, size, type) memset(array, value, ((size) + 5) * sizeof(type))
#define memarray(array, value) memset(array, value, sizeof(array))
#define fillarray(array, value, begin, end) fill((array) + (begin), (array) + (end) + 1, value)
#define fillvector(v, value) fill((v).begin(), (v).end(), value)
#define pb(x) push_back(x)
#define st(x) (1LL << (x))
#define pii pair<int, int>
#define mp(a, b) make_pair((a), (b))
#define Flush fflush(stdout)
#define vecfirst (*vec.begin())
#define veclast (*vec.rbegin())
#define vecall(v) (v).begin(), (v).end()
#define vecupsort(v) (sort((v).begin(), (v).end()))
#define vecdownsort(v, type) (sort(vecall(v), greater<type>()))
#define veccmpsort(v, cmp) (sort(vecall(v), cmp))
using namespace std;
const int N = 300050;
const int inf = 0x3f3f3f3f;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int MOD = 1e9 + 7;
const double PI = acos(-1.0);
clock_t TIME__START, TIME__END;
void program_end()
{
#ifdef ONLINE
    printf("\n\nTime used: %.6lf(s)\n", ((double)TIME__END - TIME__START) / 1000);
    system("pause");
#endif
}
const int SIZ = 50000000 + 3;
char buf1[SIZ];
char *p1 = buf1, *p2 = buf1;
inline char readchar()
{
    if (p1 == p2)
        p1 = buf1, p2 = buf1 + fread(buf1, 1, SIZ, stdin);
    return p1 == p2 ? EOF : *p1++;
}
inline int read()
{
    int ret, c;
    while ((c = readchar()) > '9' || c < '0')
        ;
    ret = c - '0';
    while ((c = readchar()) >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return ret;
}

int n, Q, a[N];
int euler[N << 1], tim, in[N], out[N];
int belong[N << 1], B, bl[1050], br[1050];
struct querys
{
    int id;
    int u, v, l, r, lca;
    int L, R;
    querys() {}
    querys(int id, int u, int v, int l, int r) : id(id), u(u), v(v), l(l), r(r) {}
    bool operator<(const querys &rhs) const
    {
        return belong[L] != belong[rhs.L] ? L < rhs.L : ((belong[L] & 1) ? R < rhs.R : R > rhs.R);
    }
} q[N];
const int MAXN = 300050, MAXM = 600050;
struct Edge
{
    int v, nxt;
} e[MAXM];
int head[MAXN], ecnt;
void add_edge(int u, int v)
{
    e[++ecnt] = {v, head[u]}, head[u] = ecnt;
    e[++ecnt] = {u, head[v]}, head[v] = ecnt;
}
int dep[MAXN], fa[MAXN][20], dfn[MAXN], dfncnt, m;
void LCA_pre_dfs(int u, int f, int d)
{
    dep[u] = d;
    fa[u][0] = f;
    dfn[u] = ++dfncnt;
    euler[++tim] = u;
    in[u] = tim;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        if (e[i].v != f)
            LCA_pre_dfs(e[i].v, u, d + 1);
    }
    euler[++tim] = u;
    out[u] = tim;
}
int ans[N];
void LCA_pre()
{
    LCA_pre_dfs(1, 0, 1);
    for (int j = 1; j <= 19; j++)
        for (int i = 1; i <= n; i++)
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
inline int getlca(int u, int v)
{
    if (dep[u] < dep[v])
        swap(u, v);
    int delta = dep[u] - dep[v];
    for (int i = 19; i >= 0; i--)
        if ((delta >> i) & 1)
            u = fa[u][i];
    for (int i = 19; i >= 0; i--)
        if (fa[u][i] ^ fa[v][i])
        {
            u = fa[u][i];
            v = fa[v][i];
        }
    if (u == v)
        return u;
    return fa[u][0];
}
int tt[1050];
inline void update(int &c, int val)
{
    tt[belong[c]] += val;
}
int used[N], cnt[N];
inline void add(int &c)
{
    if (cnt[a[c]] & 1)
        update(a[c], -1);
    cnt[a[c]]++;
    if (cnt[a[c]] & 1)
        update(a[c], 1);
}
inline void del(int &c)
{
    if (cnt[a[c]] & 1)
        update(a[c], -1);
    cnt[a[c]]--;
    if (cnt[a[c]] & 1)
        update(a[c], 1);
}
inline void Add(int &c)
{
    used[c] ? del(c) : add(c);
    used[c] ^= 1;
}
inline void getans(const querys &nowq)
{
    int lca = nowq.lca, l = nowq.l, r = nowq.r;
    if (lca)
    {
        int c = lca;
        if (cnt[a[c]] & 1)
            update(a[c], -1);
        cnt[a[c]]++;
        if (cnt[a[c]] & 1)
            update(a[c], 1);
    }
    int res = -1;
    if (belong[l] == belong[r] || belong[l] == belong[r] - 1)
    {
        for (int i = l; i <= r; ++i)
            if (cnt[i] & 1)
            {
                res = i;
                break;
            }
    }
    else
    {
        for (int i = l; belong[i] <= belong[l]; ++i)
        {
            if (cnt[i] & 1)
            {
                res = i;
                break;
            }
        }
        if (res == -1)
        {
            for (int i = r; belong[i] >= belong[r]; --i)
            {
                if (cnt[i] & 1)
                {
                    res = i;
                    break;
                }
            }
        }
        if (res == -1)
        {
            for (int i = belong[l] + 1; i < belong[r]; ++i)
            {
                if (tt[i])
                {
                    for (int j = bl[i]; j <= br[i]; ++j)
                        if (cnt[j] & 1)
                        {
                            res = j;
                            break;
                        }
                    break;
                }
            }
        }
    }
    ans[nowq.id] = res;
    if (lca)
    {
        int c = lca;
        if (cnt[a[c]] & 1)
            update(a[c], -1);
        cnt[a[c]]--;
        if (cnt[a[c]] & 1)
            update(a[c], 1);
    }
}

inline void solve()
{
    memarray(ans, -1), memarray(bl, inf);
    n = read(), Q = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    for (int i = 1; i < n; ++i)
    {
        int x = read(), y = read();
        add_edge(x, y);
    }
    LCA_pre();
    for (int i = 1; i <= Q; ++i)
    {
        int u, v, l, r;
        u = read(), v = read(), l = read(), r = read();
        q[i] = (querys){i, u, v, l, r};
        int _lca = getlca(u, v);
        if (in[u] > in[v])
            swap(u, v);
        if (_lca == u || _lca == v)
            q[i].L = in[u], q[i].R = in[v];
        else
            q[i].L = out[u], q[i].R = in[v], q[i].lca = _lca;
    }
    B = 2000;
    for (int i = 1; i <= n * 2; ++i)
    {
        belong[i] = i / B + 1;
        if (i <= n)
            bl[belong[i]] = min(bl[belong[i]], i), br[belong[i]] = max(br[belong[i]], i);
    }
    sort(q + 1, q + Q + 1);
    int L = 1, R = 0;
    for (int i = 1; i <= Q; ++i)
    {
        while (L > q[i].L)
            --L, Add(euler[L]);
        while (R > q[i].R)
            Add(euler[R]), --R;
        while (R < q[i].R)
            ++R, Add(euler[R]);
        while (L < q[i].L)
            Add(euler[L]), ++L;
        getans(q[i]);
    }
    for (int i = 1; i <= Q; ++i)
        printf("%d\n", ans[i]);
}

int main()
{
    TIME__START = clock();
    int Test = 1;
    // scanf("%d", &Test);
    while (Test--)
    {
        solve();
        // if (Test)
        //     putchar('\n');
    }
    TIME__END = clock();
    program_end();
    return 0;
}

[Codeforces Round #700(Div.1)] 1479D – Odd Mineral Resource》上有1个想法

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注