萌新刚学OI,AHOI2022这题挂成60pts,求助
查看原帖
萌新刚学OI,AHOI2022这题挂成60pts,求助
95625
暴力出奇迹楼主2022/5/9 21:29

过了 n5000n \le 5000 和特殊性质 AA60pts60pts,剩余 WA 了,进队就差这 40pts40pts

现场代码:

/*
#include <cstdio>
using namespace std;
const int N = 500010;
const int LOGN = 20;
struct Edge {
    int to, nxt;
}edges[N << 1];
int occ[N];
int lis[N], k;
int fa[N][LOGN], depth[N];
int cnt[N];
int op[N], col[N];
int head[N], n, q, nedge;
inline void swap(int &x, int &y) {x ^= y; y ^= x; x ^= y;}
inline void addedge(int u, int v) {
    edges[++nedge].to = v;
    edges[nedge].nxt = head[u];
    head[u] = nedge;
}
inline int LCA(int x, int y) {
    if(depth[x] < depth[y]) swap(x, y);
    for(int i = LOGN - 1; i >= 0; --i)
        if((1 << i) <= depth[x] - depth[y]) x = fa[x][i];
    if(x == y) return x;
    for(int i = LOGN - 1; i >= 0; --i)
        if(fa[x][i] != fa[y][i]) {x = fa[x][i]; y = fa[y][i];}
    return fa[x][0];
}
inline void dfs(int u) {
    for(int i = 1; (1 << i) <= depth[u]; ++i)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for(int i = head[u]; i; i = edges[i].nxt) {
        int v = edges[i].to;
        if(fa[u][0] == v) continue;
        fa[v][0] = u; depth[v] = depth[u] + 1;
        dfs(v);
    }
}
int main() {
    freopen("keys.in", "r", stdin);
    freopen("keys.out", "w", stdout);
    scanf("%d %d", &n, &q);
    for(int i = 1; i <= n; ++i) scanf("%d %d", &op[i], &col[i]);
    for(int i = 1; i < n; ++i) {
        int u, v; scanf("%d %d", &u, &v);
        addedge(u, v); addedge(v, u);
    }
    dfs(1);
    while(q--) {
        int u, v; scanf("%d %d", &u, &v);
        int u0 = u, v0 = v;
        int lc = LCA(u, v); int dis = depth[u] + depth[v] - 2 * depth[lc] + 1;
//        printf("u=%d, v=%d, lc=%d\n", u, v, lc);
        k = 0;
        while(true) {
            lis[++k] = u;
            if(u == lc) break;
            u = fa[u][0];
        }
        while(v != lc) {lis[dis--] = v; v = fa[v][0];}
        for(int i = 1; i <= n; ++i) occ[i] = 0;
        dis = depth[u0] + depth[v0] - 2 * depth[lc] + 1;
        int ans = 0;
//        printf("dis=%d\n", dis);
        for(int i = 1; i <= dis; ++i) {
//            printf("path: u=%d, op=%d, col=%d\n", lis[i], op[lis[i]], col[lis[i]]);
            if(op[lis[i]] == 1) ++occ[col[lis[i]]];
            else if(occ[col[lis[i]]] > 0) {++ans; --occ[col[lis[i]]];}
        }
        printf("%d\n", ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
*/

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 500010;
const int M = N * 40;
const int Q = 1000010;
const int LOGN = 20;
const int inf = 1e9 + 10;
struct Edge {
    int to, nxt;
}edges[N << 1], edges2[N << 1];
struct Operation {
    int y, dir;
}oper[M]; int nopt;
struct Question {
    int x, y;
}que[Q]; int final_answer[Q];
int headque[Q], nxtque[Q];
int headop[N], nxtop[M];
vector<int> keys, money;
int lg[N];
int stk[N], par[N];
int sum[N], top[N], heavy[N], dfn2[N], siz[N], tim2;
int lis[N], k;
int dfn[N], out[N], depth[N], fa[N][LOGN], tim;
int op[N], col[N];
int nxtcol[N], headcol[N];
int head2[N], nedge2;
int head[N], n, q, nedge;
int Fenwick[N];
inline int lowbit(int x) {return x & -x;}
inline void modify(int x, int d) {
    while(x <= n) {
        Fenwick[x] += d;
        x += lowbit(x);
    }
}
inline int quest(int x) {
    int ret = 0;
    while(x) {
        ret += Fenwick[x];
        x -= lowbit(x);
    }
    return ret;
}
struct Solution1 {
    int sum, idx;
    bool operator < (const Solution1 &rhs) const {
        if(sum != rhs.sum) return sum < rhs.sum;
        return depth[idx] < depth[rhs.idx];
    }
}ST1[N][LOGN];
struct Solution2 {
    int sum, idx;
    bool operator > (const Solution2 &rhs) const {
        if(sum != rhs.sum) return sum > rhs.sum;
        return depth[idx] > depth[rhs.idx];
    }
}ST2[N][LOGN];
inline Solution1 min(Solution1 x, Solution1 y) {return x < y ? x : y;}
inline Solution2 max(Solution2 x, Solution2 y) {return x > y ? x : y;}
inline Solution1 query1(int l, int r) {
    int k = lg[r - l + 1];
    return min(ST1[l][k], ST1[r - (1 << k) + 1][k]);
}
inline Solution2 query2(int l, int r) {
    int k = lg[r - l + 1];
    return max(ST2[l][k], ST2[r - (1 << k) + 1][k]);
}
inline bool cmp(int x, int y) {return dfn[x] < dfn[y];}
inline void addedge(int u, int v) {
    edges[++nedge].to = v;
    edges[nedge].nxt = head[u];
    head[u] = nedge;
}
inline void addedge2(int u, int v) {
//    printf("addedge2(u=%d, v=%d)\n", u, v);
    edges2[++nedge2].to = v;
    edges2[nedge2].nxt = head2[u];
    head2[u] = nedge2;
}
inline void addoper(int l1, int r1, int l2, int r2) {
    oper[++nopt] = (Operation){l2, 1};
    nxtop[nopt] = headop[l1]; headop[l1] = nopt;
    oper[++nopt] = (Operation){l2, -1};
    nxtop[nopt] = headop[r1 + 1]; headop[r1 + 1] = nopt;
    oper[++nopt] = (Operation){r2 + 1, -1};
    nxtop[nopt] = headop[l1]; headop[l1] = nopt;
    oper[++nopt] = (Operation){r2 + 1, 1};
    nxtop[nopt] = headop[r1 + 1]; headop[r1 + 1] = nopt;
//    printf("addoper(l1=%d, r1=%d, l2=%d, r2=%d)\n", l1, r1, l2, r2);
}
inline void swap(int &x, int &y) {x ^= y; y ^= x; x ^= y;}
inline int LCA(int x, int y) {
    if(depth[x] < depth[y]) swap(x, y);
    for(int i = LOGN - 1; i >= 0; --i)
        if((1 << i) <= depth[x] - depth[y]) x = fa[x][i];
    if(x == y) return x;
    for(int i = LOGN - 1; i >= 0; --i)
        if(fa[x][i] != fa[y][i]) {x = fa[x][i]; y = fa[y][i];}
    return fa[x][0];
}
inline int jump(int x, int k) {
    for(int i = LOGN - 1; i >= 0; --i)
        if(k & (1 << i)) x = fa[x][i];
    return x;
}
inline void dfs0(int u) {
    dfn[u] = ++tim;
    for(int i = 1; (1 << i) <= depth[u]; ++i)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for(int i = head[u]; i; i = edges[i].nxt) {
        int v = edges[i].to;
        if(fa[u][0] == v) continue;
        fa[v][0] = u; depth[v] = depth[u] + 1;
        dfs0(v);
    }
    out[u] = tim;
}
inline void dfs(int u, int c) {
    sum[u] = sum[par[u]] + (col[u] == c ? (op[u] == 1 ? 1 : -1) : 0);
//    printf("sum[u=%d]=%d\n", u, sum[u]);
    siz[u] = 1; heavy[u] = 0;
    for(int i = head2[u]; i; i = edges2[i].nxt) {
        int v = edges2[i].to;
        par[v] = u; dfs(v, c);
        siz[u] += siz[v];
        if(siz[v] > siz[heavy[u]]) heavy[u] = v;
    }
}
inline void dfs2(int u, int t) {
    dfn2[u] = ++tim2;
    top[u] = t;
    ST1[tim2][0] = (Solution1){sum[u], u};
    ST2[tim2][0] = (Solution2){sum[u], u};
    if(!heavy[u]) return;
    dfs2(heavy[u], t);
    for(int i = head2[u]; i; i = edges2[i].nxt) {
        int v = edges2[i].to;
        if(heavy[u] == v) continue;
        dfs2(v, v);
    }
}
inline void clear_tree(int u) {
    for(int i = head2[u]; i; i = edges2[i].nxt) {
        int v = edges2[i].to;
        clear_tree(v);
    }
    par[u] = head2[u] = dfn2[u] = top[u] = sum[u] = siz[u] = heavy[u] = 0;
}
inline Solution1 doit1(int x, int y) {
    Solution1 ret = (Solution1){inf, -1};
    while(top[x] != top[y]) {
        ret = min(ret, query1(dfn2[top[x]], dfn2[x]));
        x = par[top[x]];
    }
    ret = min(ret, query1(dfn2[y], dfn2[x]));
    return ret;
}
inline Solution2 doit2(int x, int y) {
    Solution2 ret = (Solution2){-inf, -1};
//    printf("x=%d, y=%d\n", x, y);
    while(top[x] != top[y]) {
        if(x > 0)
//            printf("x=%d, y=%d, top[x]=%d, top[y]=%d\n", x, y, top[x], top[y]);
        ret = max(ret, query2(dfn2[top[x]], dfn2[x]));
        x = par[top[x]];
    }
    ret = max(ret, query2(dfn2[y], dfn2[x]));
    return ret;
}
int main() {
    freopen("keys.in", "r", stdin);
    freopen("keys.out", "w", stdout);
    scanf("%d %d", &n, &q);
    for(int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    for(int i = 1; i <= n; ++i) scanf("%d %d", &op[i], &col[i]);
    for(int i = 1; i < n; ++i) {
        int u, v; scanf("%d %d", &u, &v);
        addedge(u, v); addedge(v, u);
    }
    dfs0(1);
//    for(int u = 1; u <= n; ++u)
//        printf("dfn[u=%d]=%d\n", u, dfn[u]);
    for(int i = 1; i <= n; ++i) {
        nxtcol[i] = headcol[col[i]];
        headcol[col[i]] = i;
    }
    for(int c = 1; c <= n; ++c) {
        if(!headcol[c]) continue; k = 0;
        for(int i = headcol[c]; i; i = nxtcol[i]) lis[++k] = i;
        keys.clear(); money.clear();
        for(int i = headcol[c]; i; i = nxtcol[i])
            if(op[i] == 1) keys.push_back(i);
            else money.push_back(i);
        sort(&lis[1], &lis[k + 1], cmp);
        int top = 1; stk[1] = lis[1];
        for(int i = 2; i <= k; ++i) {
            int u = lis[i]; int lc = LCA(u, stk[top]);
//            printf("u=%d, stk[top]=%d, lc=%d\n", u, stk[top], lc);
            while(top > 1 && depth[stk[top - 1]] > depth[lc]) {
                addedge2(stk[top - 1], stk[top]);
                --top;
            }
            if(stk[top] == lc) stk[++top] = u;
            else if(stk[top - 1] == lc) {
                addedge2(stk[top - 1], stk[top]);
                stk[top] = u;
            } else {
                addedge2(lc, stk[top]);
                stk[top] = lc; stk[++top] = u;
            }
        }
        while(top > 1) {addedge2(stk[top - 1], stk[top]); --top;}
        tim2 = 0; dfs(stk[1], c); dfs2(stk[1], stk[1]);
        par[stk[1]] = 0;
        for(int i = tim2; i; --i)
            for(int j = 1; j <= lg[tim2 - i + 1]; ++j) {
                ST1[i][j] = min(ST1[i][j - 1], ST1[i + (1 << (j - 1))][j - 1]);
                ST2[i][j] = max(ST2[i][j - 1], ST2[i + (1 << (j - 1))][j - 1]);
            }
        for(int i = 0; i < keys.size(); ++i)
            for(int j = 0; j < money.size(); ++j) {
                int x = keys[i], y = money[j];
//                printf("x=%d, y=%d\n", x, y);
//                printf("pre: x=%d, y=%d\n", x, y);
                if(dfn[x] <= dfn[y] && dfn[y] <= out[x]) {
//                    printf("case 1\n");
                    if(sum[y] != sum[par[x]]) continue;
                    Solution1 res = doit1(y, x);
                    if(res.idx == y) {
//                        printf("case 1: x=%d, y=%d\n", x, y);
                        int z = jump(y, depth[y] - depth[x] - 1);
//                        printf("z=%d\n", z);
                        addoper(1, dfn[z] - 1, dfn[y], out[y]);
                        addoper(out[z] + 1, n, dfn[y], out[y]);
                    }
                } else if(dfn[y] <= dfn[x] && dfn[x] <= out[y]) {
//                    printf("case 2\n");
                    if(sum[x] != sum[par[y]]) continue;
//                    printf("ok0\n");
                    Solution2 res = doit2(par[x], y);
//                    printf("ok1\n");
                    res = max(res, (Solution2){sum[par[y]], par[y]});
//                    printf("ok2\n");
                    if(res.idx == par[y]) {
//                        printf("case 2: x=%d, y=%d\n", x, y);
                        int z = jump(x, depth[x] - depth[y] - 1);
                        addoper(dfn[x], out[x], 1, dfn[z] - 1);
                        addoper(dfn[x], out[x], out[z] + 1, n);
                    }
                } else {
//                    printf("case 3\n");
                    int lc = LCA(x, y);
//                    printf("lc=%d\n", lc);
                    if(sum[x] + sum[y] - sum[lc] - sum[par[lc]] != 0) continue;
//                    printf("step 1 ok\n");
                    Solution2 res2 = doit2(par[x], lc);
                    res2 = max(res2, (Solution2){sum[par[x]], par[x]});
                    if(sum[x] - res2.sum < 0) continue;
                    Solution1 res1 = doit1(y, lc);
                    if(res1.idx == y) {
//                        printf("case 3: x=%d, y=%d\n", x, y);
                        addoper(dfn[x], out[x], dfn[y], out[y]);
                    }
                }
//                printf("ok\n");
            }
        clear_tree(stk[1]); nedge2 = 0;
    }
//    for(int i = 1; i <= nopt; ++i) {
//        nxtop[i] = headop[oper[i].x];
//        headop[oper[i].x] = i;
//    }
    for(int i = 1; i <= q; ++i) {
        int x, y; scanf("%d %d", &x, &y);
        que[i].x = dfn[x]; que[i].y = dfn[y];
    }
    for(int i = 1; i <= q; ++i) {
        nxtque[i] = headque[que[i].x];
        headque[que[i].x] = i;
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = headop[i]; j; j = nxtop[j]) {
            int y = oper[j].y, d = oper[j].dir;
            modify(y, d);
        }
        for(int j = headque[i]; j; j = nxtque[j])
            final_answer[j] = quest(que[j].y);
    }
    for(int i = 1; i <= q; ++i)
        printf("%d\n", final_answer[i]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

已知的“错误”是调试信息有一处没有注释掉(函数 doit2doit2 里的 if(x>0)if(x>0)),但是冷静分析了一波,发现 x>0x>0 恒成立,所以并不影响结果,事实上注释掉之后也还是 60pts60pts

2022/5/9 21:29
加载中...