Manthan, Codefest 16(G. Yash And Trees(dfs序+线段树+bitset))

题意:给你一棵树, 根结点为1, q组操作, 每组操作有两种, 一种是对一个结点的所有子树结点的值全部+1, 另一种是查询一个结点的子树结点上值%m的余数为素数的个数。

思路:对于第一个操作, 我们可以想到用dfs序给树重新标号, 使得一个结点的子树结点为相邻的一条线段, 这样,就可以很容易的用线段树进行处理了。  对于第二个操作, 为了维护一个区间内的值, 我们可以用bitset作为结点信息。  我们可以开一个m位的bitset, 对于每个位, 1表示这个数在此区间中, 最后用素数表和答案交一下就行了。

对于加一个数这个操作, 因为我们只需要m的余数, 我们可以考虑用位运算循环移位。  S << x 表示把集合S左移x位,相当于把每个数加了x, S >> m - x, 表示右移m - x位, 这样, 两者并, 就等价于第一个操作, 注意, bitset里的二进制位和整数是一样的, 高位在左, 低位在右。

细节参见代码:

[cpp]  view plain  copy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<algorithm>  
  4. #include<iostream>  
  5. #include<string>  
  6. #include<vector>  
  7. #include<stack>  
  8. #include<bitset>  
  9. #include<cstdlib>  
  10. #include<cmath>  
  11. #include<set>  
  12. #include<list>  
  13. #include<deque>  
  14. #include<map>  
  15. #include<queue>  
  16. #define Max(a,b) ((a)>(b)?(a):(b))  
  17. #define Min(a,b) ((a)<(b)?(a):(b))  
  18. using namespace std;  
  19. typedef long long ll;  
  20. typedef long double ld;  
  21. #define M 1010  
  22. typedef bitset<M> bt;  
  23. const ld eps = 1e-9, PI = 3.1415926535897932384626433832795;  
  24. const int mod = 1000000000 + 7;  
  25. const int INF = int(1e9);  
  26. // & 0x7FFFFFFF  
  27. const int seed = 131;  
  28. const ll INF64 = ll(1e18);  
  29. const int maxn = 1e5 + 10;  
  30. int T,n,m,cnt=0,addv[maxn<<2],id[maxn],last[maxn],a[maxn],b[maxn],vis[M];  
  31. bt sum[maxn<<2], res;  
  32. void PushUp(int o) {  
  33.     sum[o] = sum[o<<1] | sum[o<<1|1];  
  34. }  
  35. void add(int& a, int b) {  
  36.     a += b;  
  37.     if(a >= m) a -= m;  
  38. }  
  39. void change(bt &x, int y) {  
  40.     x = (x << y) | (x >> m - y);  
  41. }  
  42. void pushdown(int o) {  
  43.     if(addv[o]) {  
  44.         add(addv[o<<1], addv[o]);  
  45.         add(addv[o<<1|1], addv[o]);  
  46.         change(sum[o<<1], addv[o]);  
  47.         change(sum[o<<1|1], addv[o]);  
  48.         addv[o] = 0;  
  49.     }  
  50. }  
  51. void build(int l, int r, int o) {  
  52.     int m = (l + r) >> 1;  
  53.     addv[o] = 0;  
  54.     sum[o].reset();  
  55.     if(l == r) {  
  56.         sum[o][b[l]] = 1;  
  57.         return ;  
  58.     }  
  59.     build(l, m, o<<1);  
  60.     build(m+1, r, o<<1|1);  
  61.     PushUp(o);  
  62. }  
  63. void update(int L, int R, int v, int l, int r, int o) {  
  64.     int m = (l + r) >> 1;  
  65.     if(L <= l && r <= R) {  
  66.         add(addv[o], v);  
  67.         change(sum[o], v);  
  68.         return ;  
  69.     }  
  70.     pushdown(o);  
  71.     if(L <= m) update(L, R, v, l, m, o<<1);  
  72.     if(m < R) update(L, R, v, m+1, r, o<<1|1);  
  73.     PushUp(o);  
  74. }  
  75. bt query(int L, int R, int l, int r, int o) {  
  76.     int m = (l + r) >> 1;  
  77.     if(L <= l && r <= R) {  
  78.         return sum[o];  
  79.     }  
  80.     pushdown(o);  
  81.     bt ans;  
  82.     ans.reset();  
  83.     if(L <= m) ans |= query(L, R, l, m, o<<1);  
  84.     if(m < R) ans |= query(L, R, m+1, r, o<<1|1);  
  85.     return ans;  
  86. }  
  87. vector<int> g[maxn];  
  88.   
  89. void dfs(int u, int fa) {  
  90.     int len = g[u].size();  
  91.     id[u] = ++cnt;  
  92.     b[cnt] = a[u];  
  93.     for(int i=0;i<len;i++) {  
  94.         int v = g[u][i];  
  95.         if(v != fa) {  
  96.             dfs(v, u);  
  97.         }  
  98.     }  
  99.     last[u] = cnt;  
  100. }  
  101. void init() {  
  102.     for(int i=2;i<m;i++) if(!vis[i]) {  
  103.         res[i] = 1;  
  104.         for(int j=i*i;j<m;j+=i) vis[j] = 1;  
  105.     }  
  106.   
  107. }  
  108. int u, v, ii, x, q;  
  109. int main() {  
  110.     scanf("%d%d",&n,&m);  
  111.     init();  
  112.     for(int i=1;i<=n;i++) scanf("%d",&a[i]), a[i] %= m;  
  113.     for(int i=1;i<n;i++) {  
  114.         scanf("%d%d",&u,&v);  
  115.         g[u].push_back(v);  
  116.         g[v].push_back(u);  
  117.     }  
  118.     dfs(1, 1);  
  119.     build(1, n, 1);  
  120.     scanf("%d",&q);  
  121.     while(q--) {  
  122.         scanf("%d%d",&ii,&v);  
  123.         if(ii == 1) {  
  124.             scanf("%d",&x);  
  125.             update(id[v], last[v], x%m, 1, n, 1);  
  126.         }  
  127.         else {  
  128.             bt cur = query(id[v], last[v], 1, n, 1);  
  129.             printf("%d\n",(res & cur).count());  
  130.         }  
  131.     }  
  132.     return 0;  
  133. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值