CF 633G 线段树+bitset

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 633G 线段树+bitset相关的知识,希望对你有一定的参考价值。

大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的质数。

第一种操作非常熟悉了,把每个节点dfs过程中的pre和post做出来,对序列做线段树。维护取模也不是问题。第二种操作,可以利用bitset记录质数出现情况。所以整个线段树需要维护bitset的信息。

对于某一个bitset x,如果子树所有值需要加y,则x=(x<<y)|(x>>(m-y))

一开始写挂了几次,有一点没注意到,因为我bitset直接全都是1000,而不是m,所以上面式子左移会有问题,解决方法是做一个0到m每位都是1的全集,或者表示质数集的bitset上限做到m。

 

技术分享
  1 #include <iostream>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <string>
  5 #include <string.h>
  6 #include <stdio.h>
  7 #include <math.h>
  8 #include <stdlib.h>
  9 #include <queue>
 10 #include <stack>
 11 #include <map>
 12 #include <set>
 13 #include <ctime>
 14 #include <numeric>
 15 #include <bitset>
 16 #include <cassert>
 17 
 18 using namespace std;
 19 const int N=123456;
 20 int a[N];
 21 vector<int>edge[N];
 22 bitset<1000>bs[N<<2];
 23 bitset<1000>prime;
 24 int mark[N<<2];
 25 int L[N],R[N];
 26 int dfn=0;
 27 int m;
 28 int id[N];
 29 void dfs(int u,int f) {
 30     L[u]=++dfn;
 31     id[dfn]=u;
 32     for (int i=0;i<edge[u].size();i++) {
 33         int v=edge[u][i];
 34         if (v==f)
 35             continue;
 36         dfs(v,u);
 37     }
 38     R[u]=dfn;
 39 }
 40 void up(int rt) {
 41     bs[rt]=(bs[rt<<1]|bs[rt<<1|1]);
 42 }
 43 void add(int rt,int x) {
 44     bs[rt]=(((bs[rt]<<x))|(bs[rt]>>(m-x)));
 45 }
 46 void down(int rt) {
 47     if (mark[rt]) {
 48         add(rt<<1,mark[rt]);
 49         add(rt<<1|1,mark[rt]);
 50         mark[rt<<1]=(mark[rt<<1]+mark[rt])%m;
 51         mark[rt<<1|1]=(mark[rt<<1|1]+mark[rt])%m;
 52         mark[rt]=0;
 53     }
 54 }
 55 void build(int l,int r,int rt) {
 56     mark[rt]=0;
 57     if (l==r) {
 58         int x=a[id[l]];
 59         bs[rt].set(x);
 60         return;
 61     }
 62     int m=(l+r)>>1;
 63     build(l,m,rt<<1);
 64     build(m+1,r,rt<<1|1);
 65     up(rt);
 66 }
 67 
 68 void upd(int L,int R,int x,int l,int r,int rt) {
 69     if (L<=l&&r<=R) {
 70         add(rt,x);
 71         mark[rt]=(mark[rt]+x)%m;
 72         return;
 73     }
 74     down(rt);
 75     int m=(l+r)>>1;
 76     if (L<=m)
 77         upd(L,R,x,l,m,rt<<1);
 78     if (R>m)
 79         upd(L,R,x,m+1,r,rt<<1|1);
 80     up(rt);
 81 }
 82 bitset<1000> ans;
 83 void ask(int L,int R,int l,int r,int rt) {
 84      if (L<=l&&r<=R) {
 85         ans|=bs[rt];
 86         return;
 87     }
 88     down(rt);
 89     int m=(l+r)>>1;
 90     if (L<=m)
 91         ask(L,R,l,m,rt<<1);
 92     if (R>m)
 93         ask(L,R,m+1,r,rt<<1|1);
 94 }
 95 
 96 int main () {
 97     int n;
 98     scanf("%d %d",&n,&m);
 99     for (int i=2;i<m;i++) {
100         bool isp=true;
101         for (int j=2;isp&&j*j<=i;j++) {
102             if (i%j==0)
103                 isp=false;
104         }
105         if (isp){
106             prime.set(i);
107         }
108     }
109     for (int i=1;i<=n;i++){
110         scanf("%d",a+i);
111         a[i]%=m;
112     }
113     for (int i=1;i<n;i++) {
114         int u,v;
115         scanf("%d %d",&u,&v);
116         edge[u].push_back(v);
117         edge[v].push_back(u);
118     }
119     dfn=0;
120     dfs(1,-1);
121     build(1,n,1);
122     int Q;
123     scanf("%d",&Q);
124     while (Q--) {
125         int op;
126         scanf("%d",&op);
127         if (op==1) {
128             int u,x;
129             scanf("%d %d",&u,&x);
130             x%=m;
131             upd(L[u],R[u],x,1,n,1);
132         }
133         else {
134             int u;
135             scanf("%d",&u);
136             ans=0;
137             ask(L[u],R[u],1,n,1);
138             ans&=prime;
139             int ret=ans.count();
140             printf("%d\n",ret);
141         }
142     }
143     return 0;
144 }
View Code

 

以上是关于CF 633G 线段树+bitset的主要内容,如果未能解决你的问题,请参考以下文章

线段树分治

牛客练习赛D数学家的谜题线段树+bitset优化

数学家的迷题(bitset+线段树)

cdoj 1259 昊昊爱运动 II 线段树+bitset

CF-558E (线段树/分块)

CF-1108E2线段树