luogu P7446 [Ynoi2007] rfplca

https://www.luogu.com.cn/problem/P7446

有个地方写错了两次竟然还都过了

类似弹飞绵羊,维护从每个点第一次跳出当前块是跳到哪个节点,记为\(tt[i]\), 往前跳一次的记为\(to[i]\), 给整个块打标记的时候,如果存在一个点不能一次跳出当前块,就暴力把块重建一遍。因为每次至少往前跳一次,所以每个块最多重建\(\sqrt{n}\)次,每次重建\(\sqrt{n}\),一共\(\sqrt{n}\)个块,所以这部分的总时间复杂度是\(O(n\sqrt{n})\)的

然后找\(lca\)的时候怎么判断呢?

首先肯定是跳到同一块先,

如果当前点能一次能跳到下一块(\(to[i]<bl\)),那么记\(fa[i]=i\),否则记\(fa[i]=fa[to[i]]\)

假设\(x,y\)已经跳到同一块了,如果\(fa[x]==fa[y]\),说明\(lca\)在这一块内,并且\(tg[bx]==0\)

那么就直接\(x\)暴力跳,标记一下,\(y\)也暴力跳,找第一个标记即可

具体实现可以参考代码

code:

#include<bits/stdc++.h>
#define L(x) ((x - 1) * blo + 1)
#define R(x) min(x * blo, n)
#define N 500050
using namespace std;
int rd() {
    int x = 0; char ch = getchar();
    for(; ch < '0' || ch > '9'; ) ch = getchar();
    for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - '0'), ch = getchar();
    return x;
}
int n, to[N], tg[N], fa[N], tt[N], vis[N], gs, f[N], blo, bel[N];
void build(int id) {
    int l = L(id), r = R(id);
    for(int i = l; i <= r; i ++) to[i] = max(to[i] - tg[id], 1);
    tg[id] = 0;  f[id] = 1;
    to[1] = 0;
    for(int i = l; i <= r; i ++) {
        if(to[i] < l) tt[i] = to[i], fa[i] = i;
        else tt[i] = tt[to[i]], fa[i] = fa[to[i]], f[id] = 0;
    }
    
}
void change(int l, int r, int x) {
    int bl = bel[l], br = bel[r];
    if(bl == br) {
        for(int i = l; i <= r; i ++) to[i] = max(to[i] - x, 1);
        build(bl);
        return ;
    }

    for(int i = bl + 1; i < br; i ++) {
        tg[i] += x;
        if(!f[i]) build(i);
    }


    for(int i = l; i <= R(bl); i ++) to[i] = max(to[i] - x, 1);
    for(int i = L(br); i <= r; i ++) to[i] = max(to[i] - x, 1);
    build(bl), build(br);
}
int nxt(int x) {
    return max(1, tt[x] - tg[bel[x]]);
}

int lca(int x, int y) {
    while(1) {
        if(bel[x] == bel[y]) {
           if(fa[x] == fa[y]) {
               if(x == y) return x;
               gs ++; int id = bel[x];
               while(x >= L(id)) vis[x] = gs, x = to[x];
               while(vis[y] < gs) y = to[y];
               return y;
           } x = nxt(x), y = nxt(y);
        } else {
            if(bel[x] < bel[y]) swap(x, y);
            x = nxt(x);
        }
    }
}

int m;
int main() {
    n = rd(), m = rd(), blo = sqrt(n * 0.4) + 1;
    for(int i = 1; i <= n; i ++) bel[i] = (i - 1) / blo + 1;

    for(int i = 2; i <= n; i ++) to[i] = rd();

    for(int i = 1; i <= bel[n]; i ++) build(i);

    //printf("*%d", to[1]);
    int lst = 0;
    while(m --) {
        int o, x, y, z;
        o = rd(), x = rd(), y = rd();
        x ^= lst, y ^= lst;
        if(o == 1) {
            z = rd(), z ^= lst;
            change(x, y, z);
        } else printf("%d\n", lst = lca(x, y));
    }
    return 0;
}
上一篇:《自己动手写CPU》第五章--逻辑、移位操作与空指令的实现


下一篇:BUUCTF:[MRCTF2020]Unravel!!