luogu P5610 [Ynoi2013] 大学

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

因为一个数最多log次就会除到1,所以这题的难度其实是在快速定位上面

对于每个约数,用平衡树维护显然很方便,但是常数巨大,无法通过

发现可以用vector+并查集实现快速定位和删除
每个位置指向往后(包括自己)第一个没有被删除的位置,如果这个数被删了就指向下一个

然而vector常数还是巨大
考虑用指针实现,一开始先分配好地址
这样多交几发就可以通过了
code:

#include<bits/stdc++.h>
#define N 100050
#define M 500050
#define ll long long
using namespace std;

inline int read() {
    register int x = 0;
    register char ch = getchar();
    for(; ch < '0' || ch > '9'; ) ch = getchar();
    for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - 48), ch = getchar();
    return x;
}

int *fa[M], *d[M], b[M * 105], *now = b, gs[M];
inline void init(int id, int n) {
    for(int i = 0; i <= n; i ++) fa[id][i] = i;
}
inline int get(int id, int x) {
    if(x == gs[id]) return x;
    return fa[id][x] == x? x : fa[id][x] = get(id, fa[id][x]);
}
#define lowbit(x) (x & -x)
ll t[N];
int n, m, a[N];
inline void update(int x, int y) {
    for(; x <= n; x += lowbit(x)) t[x] += y;
}
inline ll query(int x) {
    ll ret = 0;
    for(; x; x -= lowbit(x)) ret += t[x];
    return ret;
}
int main() {
    n = read(), m = read();
    int mx = 0;
    for(int i = 1; i <= n; i ++) a[i] = read(), mx = max(mx, a[i]), gs[a[i]] ++;
    for(int i = 1; i <= mx; i ++)
        for(int j = i + i; j <= mx; j += i)
            gs[i] += gs[j];
    
    for(int i = 1; i <= mx; i ++) if(gs[i]) {
        d[i] = now; now += gs[i];
        fa[i] = now; init(i, gs[i]), now += gs[i];
        gs[i] = 0;
    }
    
    for(int i = 1; i <= n; i ++) {
        for(register int j = 1; j * j <= a[i]; j ++) if(a[i] % j == 0) {
            d[j][gs[j] ++] = i;
        //    printf("%d %d   %d\n", j, gs[j], d[j][gs[j] - 1]);
            if(j * j != a[i]) d[a[i] / j][gs[a[i] / j] ++] = i;
        }
        update(i, a[i]);
    }
    
    ll lst = 0;
    while(m --) {
        int o, l, r, x;
        o = read();
        if(o == 1) {
            l = read(), r = read(), x = read();
            l ^= lst, r ^= lst, x ^= lst;
            if(x == 1) continue;
            int pos = lower_bound(d[x], d[x] + gs[x], l) - d[x];
         //   printf("---%d  %d %d    %d %d \n", pos, fa[x][pos], d[x][pos], get(x, pos), gs[x]);
            for(int i = get(x, pos); i < gs[x] && d[x][i] <= r;) {
          //      printf("  %d\n", i);
                if(a[d[x][i]] % x == 0) {
                    update(d[x][i], a[d[x][i]] / x - a[d[x][i]]);
                    a[d[x][i]] /= x;
                }
                if(a[d[x][i]] % x != 0) fa[x][i] = i + 1;
                i = get(x, i + 1);
            }
        } else {
            l = read(), r = read();
            l ^= lst, r ^= lst;
            printf("%lld\n", lst = query(r) - query(l - 1));
        }
    }
    
    return 0;
}
posted @ 2021-09-01 07:11  lahlah  阅读(29)  评论(0编辑  收藏  举报