제출 #1349661

#제출 시각아이디문제언어결과실행 시간메모리
1349661boropotoBitaro’s Party (JOI18_bitaro)C++17
100 / 100
833 ms131732 KiB
#include <bits/stdc++.h>
using namespace std;

#pragma GCC optimize("O3,Ofast,unroll-loops")
#pragma GCC target("avx2")

static const int MAXN = 100000;
static const int MAXM = 200000;   // raise this if your m limit is larger
static const int BLOCK = 160;

struct FastInput
{
    static const int SZ = 1 << 20;
    int idx, size;
    char buf[SZ];

    FastInput() : idx(0), size(0) {}

    inline char getChar()
    {
        if (idx >= size)
        {
            size = (int)fread(buf, 1, SZ, stdin);
            idx = 0;
            if (!size) return 0;
        }
        return buf[idx++];
    }

    template <class T>
    inline void readInt(T &out)
    {
        char c;
        T sign = 1;
        T x = 0;

        c = getChar();
        while (c <= ' ' && c) c = getChar();

        if (c == '-')
        {
            sign = -1;
            c = getChar();
        }

        while (c > ' ')
        {
            x = x * 10 + (c - '0');
            c = getChar();
        }

        out = x * sign;
    }
};

struct FastOutput
{
    static const int SZ = 1 << 20;
    int idx;
    char buf[SZ];

    FastOutput() : idx(0) {}
    ~FastOutput() { flush(); }

    inline void pushChar(char c)
    {
        if (idx == SZ) flush();
        buf[idx++] = c;
    }

    inline void flush()
    {
        if (idx)
        {
            fwrite(buf, 1, idx, stdout);
            idx = 0;
        }
    }

    inline void writeInt(int x, char endc = '\n')
    {
        if (x == -1)
        {
            pushChar('-');
            pushChar('1');
            pushChar(endc);
            return;
        }

        char s[16];
        int n = 0;

        if (x == 0) s[n++] = '0';
        else
        {
            while (x)
            {
                s[n++] = char('0' + x % 10);
                x /= 10;
            }
        }

        while (n--) pushChar(s[n]);
        pushChar(endc);
    }
};

struct Item
{
    int dist, node;
};

static int n, m, q;
static int x, y;

/* reverse graph: parents of v */
static int head[MAXN + 5];
static int to[MAXM + 5];
static int nxt[MAXM + 5];
static int edges;

/* best BLOCK candidates for each node */
static Item best[MAXN + 5][BLOCK];
static unsigned char bestCnt[MAXN + 5];

/* temp storage for preprocessing */
static int seen[MAXN + 5];
static int mx[MAXN + 5];
static int seenToken;

static int touched[MAXN + 5];
static Item tmp[MAXN + 5];

/* banned nodes per query */
static int banned[MAXN + 5];
static int banToken;

/* DP for large queries */
static int dpSeen[MAXN + 5];
static int dpVal[MAXN + 5];
static int dpToken;

inline bool cmpItem(const Item &a, const Item &b)
{
    return a.dist > b.dist;
}

inline void addEdge(int u, int v)
{
    to[++edges] = u;
    nxt[edges] = head[v];
    head[v] = edges;
}

inline void preprocess()
{
    for (int node = 1; node <= n; node++)
    {
        ++seenToken;
        int touchedCnt = 0;

        seen[node] = seenToken;
        mx[node] = 0;
        touched[touchedCnt++] = node;

        for (int e = head[node]; e; e = nxt[e])
        {
            int parent = to[e];
            int cnt = bestCnt[parent];

            for (int j = 0; j < cnt; j++)
            {
                int id = best[parent][j].node;
                int d = best[parent][j].dist + 1;

                if (seen[id] != seenToken)
                {
                    seen[id] = seenToken;
                    mx[id] = d;
                    touched[touchedCnt++] = id;
                }
                else if (mx[id] < d)
                {
                    mx[id] = d;
                }
            }
        }

        for (int i = 0; i < touchedCnt; i++)
        {
            int id = touched[i];
            tmp[i] = {mx[id], id};
        }

        int keep = touchedCnt;
        if (keep > BLOCK)
        {
            nth_element(tmp, tmp + BLOCK, tmp + keep, cmpItem);
            keep = BLOCK;
        }

        sort(tmp, tmp + keep, cmpItem);

        bestCnt[node] = (unsigned char)keep;
        for (int i = 0; i < keep; i++) best[node][i] = tmp[i];
    }
}

inline int solveSmall(int target)
{
    int cnt = bestCnt[target];
    for (int i = 0; i < cnt; i++)
    {
        int node = best[target][i].node;
        if (banned[node] != banToken) return best[target][i].dist;
    }
    return -1;
}

inline int solveLarge(int target)
{
    ++dpToken;
    dpSeen[target] = dpToken;
    dpVal[target] = 0;

    int ans = (banned[target] != banToken ? 0 : -1);

    for (int node = target; node >= 1; node--)
    {
        if (dpSeen[node] != dpToken) continue;

        int cur = dpVal[node];
        if (banned[node] != banToken && cur > ans) ans = cur;

        for (int e = head[node]; e; e = nxt[e])
        {
            int parent = to[e];
            int nd = cur + 1;

            if (dpSeen[parent] != dpToken)
            {
                dpSeen[parent] = dpToken;
                dpVal[parent] = nd;
            }
            else if (dpVal[parent] < nd)
            {
                dpVal[parent] = nd;
            }
        }
    }

    return ans;
}

int main()
{
    FastInput in;
    FastOutput out;

    in.readInt(n);
    in.readInt(m);
    in.readInt(q);

    for (int i = 0; i < m; i++)
    {
        int u, v;
        in.readInt(u);
        in.readInt(v);
        addEdge(u, v);
    }

    preprocess();

    while (q--)
    {
        in.readInt(x);
        in.readInt(y);

        ++banToken;
        for (int i = 0; i < y; i++)
        {
            int a;
            in.readInt(a);
            banned[a] = banToken;
        }

        int ans = (y < BLOCK ? solveSmall(x) : solveLarge(x));
        out.writeInt(ans);
    }

    out.flush();
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...