百折不挠|

Xdik

园龄:1个月粉丝:7关注:24

CF633G

因为这道题是在树上的,所以我们很套路地先 dfs 一次 ,这样一颗子树上的结点的 dfn 就在一起了,对子树的操作就转化为对区间的操作,但是怎么数区间内出现了哪些数呢?因为是对区间加了 x 后再 mod m 所以相当于是将这个区间原本有的数整体向右移了 x 位,然后再将超过了 m 这个范围的数重新接到最前面去,因为我们只需要知道出现了哪些数而不用知道这些数出现了多少次,且注意到题面中的 m1000 ,范围比较小 所以我们就可以用一个只记录这个数是否出现过且十分方便移动的东西 : bitset 然而我当时不会用导致考场爆零 这样,我们添加操作就十分简单了,只需要对这个区间的 bitset 整体向左移 x 位,再将后面的 x 位移到前面来就可以了(具体就是将原来的 bitset 左移 x 位再或上原来的 bitset 右移 (mx) 位 ),那么统计答案的时候就将整个区间的 bitset 全部或起来,在最开始的时候创造一个 bitset 来记录哪些是质数,最后再将这两个 bitset 与起来,一的数量就是最终的答案,对于维护区间,我一开始是想写分块的,后面感觉不够快就改成了线段树,时间复杂度显然是能够通过本题的

AC Code:


#include <bits/stdc++.h>
#define ing long long
#pragma GCC optimeze(3)
#pragma GCC optimeze(2)
using namespace std;
const int N = 2e5 + 5;
int read() {
    int x = 0, flag = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            flag = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return x * flag;
}
int n, a[N], ver[N * 2], head[N], ne[N * 2], dfn[N], rk[N], cnt, tot, siz[N], m, q, sum = 0;
bool vis[1005];
bitset<1000> tr[N * 4], help, jb;
int b[N * 4];
void add(int x, int y) { ver[++tot] = y, ne[tot] = head[x], head[x] = tot; }
void dfs(int t, int f) {
    dfn[t] = ++cnt;
    rk[cnt] = t;
    siz[t] = 1;
    for (int i = head[t]; i; i = ne[i]) {
        int to = ver[i];
        if (to == f)
            continue;
        dfs(to, t);
        siz[t] += siz[to];
    }
}
void pushdown(int p) {
    tr[p * 2] = ((tr[p * 2] >> (m - b[p])) | (tr[p * 2] << b[p]));
    b[p * 2] += b[p];
    b[p * 2] %= m;
    tr[p * 2 + 1] = ((tr[p * 2 + 1] >> (m - b[p])) | (tr[p * 2 + 1] << b[p]));
    b[p * 2 + 1] += b[p];
    b[p * 2 + 1] %= m;
    b[p] = 0;
}
void pushup(int p) { tr[p] = tr[p * 2] | tr[p * 2 + 1]; }
void build(int p, int l, int r) {
    if (l == r) {
        tr[p][a[rk[l]] % m] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    pushup(p);
}
void change(int l, int r, int x, int p, int s, int t) {
    if (s >= l && t <= r) {
        tr[p] = ((tr[p] >> (m - x)) | (tr[p] << x));
        b[p] += x;
        b[p] %= m;
        return;
    }
    int mid = (s + t) >> 1;
    pushdown(p);
    if (mid >= l)
        change(l, r, x, p * 2, s, mid);
    if (mid < r)
        change(l, r, x, p * 2 + 1, mid + 1, t);
    pushup(p);
}
bitset<1000> qu(int l, int r, int p, int s, int t) {
    if (s >= l && t <= r)
        return tr[p];
    int mid = (s + t) >> 1;
    pushdown(p);
    bitset<1000> ans = help;
    if (mid >= l)
        ans |= qu(l, r, p * 2, s, mid);
    if (mid < r)
        ans |= qu(l, r, p * 2 + 1, mid + 1, t);
    return ans;
}
signed main() {
    n = read(), m = read();
    vis[1] = 1;
    for (int i = 2; i < m; i++) {
        if (!vis[i]) {
            sum++;
            jb[i] = 1;
            for (int j = 2; j * i < m; j++) {
                vis[j * i] = 1;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        a[i] = read();
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        u = read(), v = read();
        add(u, v);
        add(v, u);
    }
    dfs(1, 0);
    build(1, 1, n);
    q = read();
    while (q--) {
        int opt, v, x;
        opt = read();
        if (opt == 1) {
            v = read(), x = read();
            x %= m;
            change(dfn[v], dfn[v] + siz[v] - 1, x, 1, 1, n);
        } else {
            v = read();
            cout << (qu(dfn[v], dfn[v] + siz[v] - 1, 1, 1, n) & jb).count() << endl;
        }
    }
    return 0;
}

本文作者:Xdik

本文链接:https://www.cnblogs.com/Xdik/p/18708137

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Xdik  阅读(15)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起