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 }
以上是关于CF 633G 线段树+bitset的主要内容,如果未能解决你的问题,请参考以下文章