P4899 [IOI2018] werewolf 狼人

传送门


思路

kruskal 重构树的一个很好的应用

这道题中,我们建两棵重构树:

一棵按照边权为两点编号中的最值,建一个根堆重构树(称为树 \(a\)

一棵按照边权为两点编号中的最值,建一个根堆重构树(称为树 \(b\)

\(a\) 上叶子结点的 dfs 序为 \(da[u]\)\(b\) 上叶子结点的 dfs 序为 \(db[u]\)

在遍历树 \(b\) 到其叶子结点 \(u\) 时,我们就新建一棵权值主席树,让 \(da[u]\) 处加一

当询问 \(s,t,l,r\) 时,我们在树 \(a\)\(s\) 向上跳到最浅的点 \(x\) 使 \(val_x\ge l\),设 \(x\) 子树的 dfs 序区间为 \(al, ar\)

在再树 \(b\)\(t\) 向上跳到最浅的点 \(y\) 使 \(val_y\le r\),设 \(y\) 子树的 dfs 序区间为 \(bl, br\)

最后我们询问 \(bl\)\(br\) 的主席树中,区间 \([al,ar]\) 的个数是否大于 \(0\);如果是,代表可以从 \(s\)\(t\)

这其实就是求:从 \(s\) 出发所能到的点集,与从 \(t\) 出发所能到的点集是否有交


代码

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int reads()
{
    int sign = 1, re = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
    while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
int n, m, q;
struct Node
{
    int u, v, w;
}r[400005];
struct kruskal
{
    int fa[200005], rt[400005], val[400005], pcnt;
    std::vector<int> e[400005]; int st[400005][19];
    int in[400005], out[400005], dcnt;
    int find_fa(int x)
    {
        if(x == fa[x]) return x;
        return fa[x] = find_fa(fa[x]);
    }
    int find_rt(int x)
    {
        if(x == rt[x]) return x;
        return rt[x] = find_rt(rt[x]);
    }
    inline void Init(int i)
    {
        int x = find_fa(r[i].u), y = find_fa(r[i].v);
        if(x == y) return;
        fa[x] = y; x = find_rt(x), y = find_rt(y);
        val[++pcnt] = r[i].w; rt[pcnt] = pcnt;
        e[pcnt].emplace_back(x), e[pcnt].emplace_back(y);
        rt[x] = rt[y] = pcnt;
    }
}a, b;
void dfsa(int now)
{
    if(now <= n) a.in[now] = a.out[now] = ++a.dcnt;
    FOR(i, 1, 18)
    {
        int la = a.st[now][i - 1];
        if(!a.st[la][i - 1]) break;
        a.st[now][i] = a.st[la][i - 1];
    }
    for(int to : a.e[now])
    {
        a.st[to][0] = now;
        dfsa(to);
        if(!a.in[now]) a.in[now] = a.in[to];
        a.out[now] = a.out[to];
    }
}
namespace Seg
{
    struct Tr
    {
        int sum, ls, rs;
    }tr[6400005]; int cnt, rt[200005];
    int modify(int pre, int l, int r, int to)
    {
        int now = ++cnt;
        tr[now] = tr[pre];
        if(l == r)
        {
            tr[now].sum++;
            return now;
        }
        int mid = (l + r) >> 1;
        if(to <= mid) tr[now].ls = modify(tr[pre].ls, l, mid, to);
        else tr[now].rs = modify(tr[pre].rs, mid + 1, r, to);
        tr[now].sum = tr[tr[now].ls].sum + tr[tr[now].rs].sum;
        return now;
    }
    int query(int pre, int now, int l, int r, int L, int R)
    {
        if(L <= l && r <= R) return tr[now].sum - tr[pre].sum;
        int mid = (l + r) >> 1, re = 0;
        if(L <= mid) re += query(tr[pre].ls, tr[now].ls, l, mid, L, R);
        if(mid < R) re += query(tr[pre].rs, tr[now].rs, mid + 1, r, L, R);
        return re;
    }
}
void dfsb(int now)
{
    if(now <= n)
    {
        b.in[now] = b.out[now] = ++b.dcnt;
        Seg::rt[b.dcnt] = Seg::modify(Seg::rt[b.dcnt - 1], 1, n, a.in[now]);
    }
    FOR(i, 1, 18)
    {
        int la = b.st[now][i - 1];
        if(!b.st[la][i - 1]) break;
        b.st[now][i] = b.st[la][i - 1];
    }
    for(int to : b.e[now])
    {
        b.st[to][0] = now;
        dfsb(to);
        if(!b.in[now]) b.in[now] = b.in[to];
        b.out[now] = b.out[to];
    }
}
inline void asolve(int u, int x, int &L, int &R)
{
    ROF(i, 18, 0) if(a.st[u][i] && a.val[a.st[u][i]] >= x)
        u = a.st[u][i];
    L = a.in[u], R = a.out[u];
}
inline void bsolve(int u, int x, int &L, int &R)
{
    ROF(i, 18, 0) if(b.st[u][i] && b.val[b.st[u][i]] <= x)
        u = b.st[u][i];
    L = b.in[u], R = b.out[u];
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = reads(), m = reads(), q = reads();
    FOR(i, 1, n) a.fa[i] = a.rt[i] = b.fa[i] = b.rt[i] = i;
    a.pcnt = b.pcnt = n;
    FOR(i, 1, m)
    {
        int u = reads() + 1, v = reads() + 1;
        r[i] = (Node){u, v, std::min(u, v)};
    }
    std::sort(r + 1, r + 1 + m, [&](Node a, Node b){return a.w > b.w;});
    FOR(i, 1, m) a.Init(i);
    FOR(i, 1, m) r[i].w = std::max(r[i].u, r[i].v);
    std::sort(r + 1, r + 1 + m, [&](Node a, Node b){return a.w < b.w;});
    FOR(i, 1, m) b.Init(i);
    dfsa(a.pcnt), dfsb(b.pcnt);
    while(q--)
    {
        int s = reads() + 1, t = reads() + 1, l = reads() + 1, r = reads() + 1;
        int al, ar, bl, br;
        asolve(s, l, al, ar); bsolve(t, r, bl, br);
        if(Seg::query(Seg::rt[bl - 1], Seg::rt[br], 1, n, al, ar))
            puts("1");
        else puts("0");
    }
    return 0;
}
posted @ 2022-09-14 20:08  zuytong  阅读(19)  评论(0编辑  收藏  举报