ZOJ 3911 线段树

题意:有N个数字,M个操作,然后回答每个Q开头的询问

操作形式:

A val pos:在pos位置上+val

Q l r:询问l~r之间有多少个质数

R val l r:把l~r之间的数字替换成val

分析:建成两棵树,一棵更新 原数列,一棵更新 质数序列(只有0,1)

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5 using namespace std;
  6 #define repu(i,a,b) for(int i=a;i<b;i++)
  7 #define lson l , m , rt << 1
  8 #define rson m + 1 , r , rt << 1 | 1
  9 const int maxn = 111111;
 10 const int M = 10000010;
 11 int h , w , n;
 12 bool p[M];
 13 int prime()
 14 {
 15     memset(p,false,sizeof(p));
 16     p[0] = p[1] = true;
 17     for(int i = 4; i <= M; i += 2)
 18         p[i] = true;
 19     for(int i = 3; i <= sqrt(M); i+=2)
 20     {
 21         int k = i * 2;
 22         for(int j = i*i; j <= M; j += k)
 23             p[j] = true;
 24     }
 25 }
 26 struct Segment
 27 {
 28     int col[maxn<<2];
 29     int sum[maxn<<2];
 30     void init()
 31     {
 32         memset(col,0,sizeof(col));
 33         memset(sum,0,sizeof(sum));
 34     }
 35     void PushUp(int rt)
 36     {
 37         sum[rt] = sum[rt<<1] + sum[rt<<1|1];
 38     }
 39     void PushDown(int rt,int m)
 40     {
 41         if(col[rt] != -1)///如果是0就进不去
 42         {
 43             col[rt<<1] = col[rt<<1|1] = col[rt];
 44             sum[rt<<1] = (m - (m >> 1)) * col[rt];
 45             sum[rt<<1|1] = (m >> 1) * col[rt];
 46             col[rt] = -1;
 47         }
 48     }
 49     void build(int l,int r,int rt)
 50     {
 51         col[rt] = -1;
 52         sum[rt] = 0;
 53         if (l == r) return ;
 54         int m = (l + r) >> 1;
 55         build(lson);
 56         build(rson);
 57         PushUp(rt);
 58     }
 59     void Update(int p,int add,int l,int r,int rt)
 60     {
 61         if(l == r)
 62         {
 63             sum[rt] += add;
 64             return ;
 65         }
 66         PushDown(rt , r - l + 1);
 67         int m = (l + r) >> 1;
 68         if (p <= m) Update(p, add, lson);
 69         else Update(p, add, rson);
 70         PushUp(rt);
 71     }
 72     void update(int L,int R,int c,int l,int r,int rt)
 73     {
 74         if (L <= l && r <= R)
 75         {
 76             col[rt] = c;
 77             ///因为序列只有0,1;如果初始化为0的话,赋值有可能赋成0,pushdown就进不了,也就跟新不了数据了
 78             sum[rt] = c * (r - l + 1);
 79             return ;
 80         }
 81         PushDown(rt , r - l + 1);
 82         int m = (l + r) >> 1;
 83         if (L <= m) update(L , R , c , lson);
 84         if (R > m) update(L , R , c , rson);
 85         PushUp(rt);
 86     }
 87     int query(int L,int R,int l,int r,int rt)
 88     {
 89         if (L <= l && r <= R)
 90         {
 91             return sum[rt];
 92         }
 93         PushDown(rt , r - l + 1);
 94         int m = (l + r) >> 1;
 95         int ret = 0;
 96         if (L <= m) ret += query(L , R , lson);
 97         if (m < R) ret += query(L , R , rson);
 98         PushUp(rt);
 99         return ret;
100     }
101 } Seg,seg;
102 int main()
103 {
104     int T , n , m, a , b , c;
105     prime();
106     scanf("%d",&T);
107     for (int cas = 1 ; cas <= T ; cas ++)
108     {
109         Seg.init();
110         seg.init();
111         scanf("%d%d",&n,&m);
112         Seg.build(1 , n , 1);
113         seg.build(1 , n , 1);
114         repu(i,1,n+1)
115         {
116             scanf("%d",&a);
117             Seg.Update(i,a,1,n,1);
118             if(!p[a])///如果是质数才加1
119                 seg.Update(i,1,1,n,1);
120         }
121         char s[4];
122         while(m--)
123         {
124             scanf("%s",s);
125             if(s[0] == ‘R‘)
126             {
127                 scanf("%d%d%d",&a, &b, &c);
128                 Seg.update(b , c , a , 1 , n , 1);
129                 if(!p[a])///如果是质数,更新成1
130                     seg.update(b , c , 1 , 1 , n , 1);
131                 else
132                     seg.update(b , c , 0 , 1 , n , 1);
133             }
134             else if(s[0] == ‘A‘)
135             {
136                 scanf("%d%d",&a,&b);///在b位置上加a,如果加的数字成了质数,也得更新另一棵树
137                 int t = Seg.query(b,b,1,n,1);
138                 Seg.Update(b,a,1,n,1);
139                 if(!p[t+a] && p[t])///原本不是质数,变成了质数
140                     seg.Update(b,1,1,n,1);
141                 else if(p[t+a] && !p[t])///原本是质数,变成了合数
142                     seg.Update(b,-1,1,n,1);
143                 else if(p[t+a] && p[t]) ;
144                 else if(!p[t+a] && !p[t]) ;
145             }
146             else
147             {
148                 scanf("%d%d",&a,&b);
149                 printf("%d\n",seg.query(a,b,1,n,1));
150             }
151         }
152     }
153     return 0;
154 }

AC代码

时间: 2024-10-10 10:52:12

ZOJ 3911 线段树的相关文章

ZOJ 3635 线段树

线段树维护的是区间有多少个空位置,每次查询第X个空位置在哪,sum[rt]>=X就向左区间找,sum[rt]<X就向又区间找. #include <cstdio> #include <algorithm> #include <iostream> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int

ZOJ 1610 线段树区间染色

给长度8000米的板,对其中区间染色,问最后能看到的颜色,和该颜色一共出现了几段 线段覆盖法 数据比较水   也可以暴力水过 线段树: #include "stdio.h" #include "string.h" struct node { int l,r,c; }data[40010]; int color[8011]; void build(int l,int r,int k) { int mid; data[k].l=l; data[k].r=r; data[

zoj 1610 线段树

用线段树进行区间赋值,最后将每个小segment的颜色求出来,再扫一遍判断连续的段数即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 8001; 7 int color[N]; 8 int ans[N]; 9 10 struct Node 11 { 12 int l, r, c; 13 } node[N &

zoj 3888 线段树 ***

卡n^2,用线段树降到nlogn 记录每个点上所覆盖线段的次小值,保证能有两条路径能走 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MO

HDU 3911 线段树区间合并

北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #include<iostream> #include<cstdio> #include<map> #include<set> #include<cmath> #define lson id << 1 #define rson id <<

ZOJ 3772 线段树

点击打开链接 题意:给一个数字序列,然后有m次询问,每次询问给了一个递推关系,然后输出询问的R的值 思路:n是100000,m是100000,然后来询问,就算不知道题意肯定也要向线段树这方面来想,而线段树的应用无非就是节点保存的信息嘛,这道题目要的是一段连续的递推式子,那么我们的节点就可以保存递推式,而这个式子也很好推,看代码应该可以看得懂,然后飞根节点保存的就是两个儿子的矩阵乘积后的矩阵,然后就是模版式的线段树,难点应该就是线段树的节点的内容嘛,而苦逼的我并不懂矩阵乘法的一些注意点,写完后无情

Count the Colors (zoj 1610 线段树 区间颜色覆盖)

Count the Colors Time Limit: 2 Seconds      Memory Limit: 65536 KB Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different colors you can s

HDOJ 3911 线段树

链接: http://acm.hdu.edu.cn/showproblem.php?pid=3911 题意: 给出01串 1代表黑色 0代表白色 0 a b:询问[a,b]中1的连续最大长度 1 a,b:把[a,b]区间的0->1 1->0 题解: lsum1[],rsum1[],msum1[]分别表示区间左起连续1的最大长度,右起连续1的最大长度,区间1的最大连续长度 lsum0[],rsum0[],msum0[]分别表示区间左起连续0的最大长度,右起连续0的最大长度,区间连续0的最大连续长

HDU 1199 &amp;amp;&amp;amp; ZOJ 2301 线段树离散化

一段长度未知的线段.一种操作:a b c ,表示区间[a,b]涂为颜色C,w代表白色,b代表黑色,问终于的最长连续白色段,输出起始位置和终止位置 离散化处理.和寻常的离散化不同,须要把点化成线段.左闭右开,即对于一段区间[a.b],转化成区间[a,b+1) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct node { i