G. Yash And Trees 线段树 + dfs序 + bitset
这个是要用bitset 一个大整数的二进制 学习推荐博客
这个题目大意就是:给你n,m 还有一个序列,还有一个一棵树,有一种操作一种询问
操作是给你一个节点 把这个节点及其子节点都加上x
询问是 给你一个节点,问你这个节点以下 小于m的质数有多少种,注意是种,所以要去重,所以需要bitset
这个题目我写了一上午,wa了一下午,在lj的帮助之下终于写出来了。
写法,操作就可以用<< 来代替加上x,但是因为如果超出了m,就要对m取模,所以相当于一个环,这个环的处理要注意。
注意:
我wa的地方:
忘记了update 的push_up 操作,
query的两个区间合起来的时候没有去重。
还有就是 << 这个操作,因为素数一定要小于m,而且每一个数一定小于m,所以<<m,就可以了,而且素数的bitset 只要到m-1就可以了
最后一个最重要的!!!
我建树建错了,这个dfs序之后,如果我想把给的a序列放进来,那么就需要按照dfs序来,所以dfs序,不仅仅要存每一个数映射的位置,而且要存每一个位置存的数。
建树要注意!!! 第一次碰到这个问题,以后希望不要再这样wa一下午了,
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <bitset> #include <vector> #include <queue> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 1e5 + 10; const int mx = 2200; bitset<mx>B; bitset<mx>C; bitset<mx>ex; struct node { bitset<mx>bt; ll lazy; }tree[maxn*4]; int n, m, q, p[maxn]; ll a[maxn]; //素数筛 void init() { for (int i = 2; i < maxn; i++) p[i] = 1; for (int i = 2; i*i < maxn; i++) { if (p[i]) { for (int j = i * i; j < maxn; j += i) { p[j] = 0; } } } B.reset(); C.reset(); for (int i = 0; i < m; i++) { if (p[i]) B.set(i);//B构造出一个全部都是素数的bitset C.set(i); } } //v数组记录每一个i的最小质因数,isp记录所有的质数 int er[maxn], el[maxn], tot; vector<int>G[maxn]; bool vis[maxn]; int num[maxn]; //dfs序 转化成二叉树 void dfs(int x) { vis[x] = 1; el[x] = ++tot; num[tot] = x; for(int i=0;i<G[x].size();i++) { int v = G[x][i]; if (vis[v]) continue; dfs(v); } er[x] = tot; } //线段树的建树过程 void build(int id,int l,int r) { tree[id].lazy = 0; if(l==r) { tree[id].bt.set(a[num[l]]); return; } int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); tree[id].bt = tree[id << 1].bt | tree[id << 1 | 1].bt; // printf("id=%d l=%d r=%d\n", id, l, r); // std::cout << tree[id].bt << endl; } void push_down(int id) { if(tree[id].lazy) { ex.reset(); int val = tree[id].lazy; tree[id << 1].bt <<= val; ex = tree[id << 1].bt >> m; tree[id << 1].bt |= ex; tree[id << 1].bt &= C; tree[id << 1].lazy += val; tree[id << 1].lazy %= m; ex.reset(); tree[id << 1 | 1].bt <<= val; ex = tree[id << 1 | 1].bt >> m; tree[id << 1 | 1].bt |= ex; tree[id << 1 | 1].bt &= C; tree[id << 1 | 1].lazy += val; tree[id << 1 | 1].lazy %= m; tree[id].lazy = 0; } } void update(int id,int l,int r,int x,int y,int val) { if(x<=l&&y>=r) { // printf("1 id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y); // std::cout << tree[id].bt << endl; ex.reset(); tree[id].lazy += val; tree[id].lazy %= m; tree[id].bt <<= val; // printf("2\n"); // std::cout << tree[id].bt << endl; ex = tree[id].bt >> m; tree[id].bt |= ex; // printf("3\n"); // std::cout << tree[id].bt << endl; tree[id].bt &= C; // printf("id=%d l=%d r=%d x=%d y=%d val=%d \n", id, l, r, x, y, val); // std::cout << tree[id].bt << endl; return; } push_down(id); int mid = (l + r) >> 1; if (x <= mid) update(id << 1, l, mid, x, y, val); if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, val); tree[id].bt = tree[id << 1].bt | tree[id << 1 | 1].bt; } bitset<mx> query(int id,int l,int r,int x,int y) { if (x <= l && y >= r) { // printf("id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y); // std::cout << tree[id].bt << endl; return tree[id].bt&B; } push_down(id); int mid = (l + r) >> 1; bitset<mx>ans; if (x <= mid) ans |= query(id << 1, l, mid, x, y); if (y > mid) ans |= query(id << 1 | 1, mid + 1, r, x, y); // printf("id=%d l=%d r=%d x=%d y=%d\n", id, l, r, x, y); // std::cout << ans << endl; return (ans & B); } int main() { tot = 0; scanf("%d%d", &n, &m); init(); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]), a[i] %= m; for(int i=1;i<n;i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } memset(vis, 0, sizeof(vis)); dfs(1); build(1, 1, n); scanf("%d", &q); while(q--) { int opt, v, x; scanf("%d", &opt); if(opt==1) { scanf("%d%d", &v, &x); x %= m; update(1, 1, n, el[v], er[v], x); } else { scanf("%d", &v); bitset<mx>ans = query(1, 1, n, el[v], er[v]); printf("%d\n", ans.count()); } } return 0; } /* 3 33 94 21 38 3 1 3 2 9 2 1 2 2 1 3 127 2 2 1 2 381 1 1 275 2 2 2 3 1 1 695 */