分块做题记录-----数列分块入门 2

题目描述

给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的元素个数。

输入格式

第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 ai​​,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

若 opt=0,表示将位于 [l, r] 的之间的数字都加 c。

若 opt=1,表示询问 [l, r] 中,小于 c^2 的数字的个数。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 1 3 2
1 1 4 1
1 2 3 2

样例输出

3
0
2

数据范围与提示

对于100% 的数据,1≤n≤50000,−2^31​​≤others、ans≤2^31−1

方法一

用vector+sort维护每个块的有序性

不完整块暴力修改后要重新排序

在LOJ上A了,然而在入门OJ上TLE了。。。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<vector>
 6 using namespace std;
 7 const int N=5e4+5;
 8 int n,len,v[N],bl[N],tag[N];
 9 vector<int> d[230];
10 int read()
11 {
12     int f=1,x=0;
13     char ch=getchar();
14     while(!isdigit(ch))
15     {
16         if(ch=='-')f=-1;
17         ch=getchar();
18     }
19     while(isdigit(ch))
20     {
21         x=x*10+ch-'0';
22         ch=getchar();
23     }
24     return x*f;
25 }
26 void up(int x)
27 {
28     d[x].clear();
29     for(int i=(x-1)*len+1; i<=min(n,x*len); i++)
30         d[x].push_back(v[i]);
31     sort(d[x].begin(),d[x].end());
32 }
33 void add(int a,int b,int c)
34 {
35     for(int i=a; i<=min(b,bl[a]*len); i++)
36         v[i]+=c;
37     up(bl[a]);
38     if(bl[a]!=bl[b])
39     {
40         for(int i=(bl[b]-1)*len+1; i<=b; i++)
41             v[i]+=c;
42         up(bl[b]);
43     }
44     for(int i=bl[a]+1; i<=bl[b]-1; i++)
45         tag[i]+=c;
46 }
47 int query(int a,int b,int c)
48 {
49     int ans=0;
50     for(int i=a; i<=min(b,bl[a]*len); i++)
51         if(v[i]+tag[bl[i]]<c)++ans;
52     if(bl[a]!=bl[b])
53         for(int i=(bl[b]-1)*len+1; i<=b; i++)
54             if(v[i]+tag[bl[i]]<c)++ans;
55     for(int i=bl[a]+1; i<=bl[b]-1; i++)
56     {
57         int x=c-tag[i];
58         ans+=lower_bound(d[i].begin(),d[i].end(),x)-d[i].begin();
59     }
60     return ans;
61 }
62 int main()
63 {
64     n=read();
65     len=sqrt(n);
66     for(int i=1; i<=n; i++)
67     {
68         v[i]=read();
69         bl[i]=(i-1)/len+1;
70         d[bl[i]].push_back(v[i]);
71     }
72     for(int i=1; i<=bl[n]; i++)
73         sort(d[i].begin(),d[i].end());
74     for(int i=1; i<=n; i++)
75     {
76         int f=read(),a=read(),b=read(),c=read();
77         if(f==0)add(a,b,c);
78         else printf("%d\n",query(a,b,c*c));
79     }
80     return 0;
81 }

方法二

对每个块维护块内最值mx和mn

统计完整块时,如果c>mx[i],ans+=len,如果c<=mn[i]就直接跳过

否则暴力统计

这个方法在入门OJ上A了

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=50010;
 8 int n,len;
 9 int v[N],bl[N],mx[300],mn[300],tag[300];
10 int read()
11 {
12     int x=0,f=1;
13     char ch=getchar();
14     while(!isdigit(ch))
15     {
16         if(ch=='-')f=-1;
17         ch=getchar();
18     }
19     while(isdigit(ch))
20     {
21         x=x*10+ch-'0';
22         ch=getchar();
23     }
24     return x*f;
25 }
26 void add(int a,int b,int c)
27 {
28     for(int i=a; i<=min(b,bl[a]*len); i++)
29     {
30         v[i]+=c;
31         mx[bl[i]]=max(mx[bl[i]],v[i]+tag[bl[i]]);
32         mn[bl[i]]=min(mn[bl[i]],v[i]+tag[bl[i]]);
33     }
34     if(bl[a]!=bl[b])
35         for(int i=(bl[b]-1)*len+1; i<=b; i++)
36         {
37             v[i]+=c;
38             mx[bl[i]]=max(mx[bl[i]],v[i]+tag[bl[i]]);
39             mn[bl[i]]=min(mn[bl[i]],v[i]+tag[bl[i]]);
40         }
41     for(int i=bl[a]+1; i<=bl[b]-1; i++)
42         tag[i]+=c,mx[i]+=c,mn[i]+=c;
43 }
44 int query(int a,int b,int c)
45 {
46     int ans=0;
47     for(int i=a; i<=min(b,bl[a]*len); i++)
48         if(v[i]+tag[bl[a]]<c)++ans;
49     if(bl[a]!=bl[b])
50         for(int i=(bl[b]-1)*len+1; i<=b; i++)
51             if(v[i]+tag[bl[b]]<c)++ans;
52     for(int i=bl[a]+1; i<=bl[b]-1; i++)
53     {
54         if(c<=mn[i])continue;
55         if(c>mx[i])ans+=len;
56         else
57         {
58             for(int j=(i-1)*len+1; j<=i*len; j++)
59                 if(v[j]+tag[i]<c)++ans;
60         }
61     }
62     return ans;
63 }
64 int main()
65 {
66     n=read();
67     len=sqrt(n);
68     memset(mn,0x3f,sizeof(mn));
69     for(int i=1; i<=n; i++)
70     {
71         v[i]=read();
72         bl[i]=(i-1)/len+1;
73         mx[bl[i]]=max(mx[bl[i]],v[i]);
74         mn[bl[i]]=min(mn[bl[i]],v[i]);
75     }
76     for(int i=1; i<=n; i++)
77     {
78         int f=read(),a=read(),b=read(),c=read();
79         if(!f)add(a,b,c);
80         else printf("%d\n",query(a,b,c*c));
81     }
82     return 0;
83 }

 

posted @ 2018-08-16 13:34  CBDfake  阅读(177)  评论(0编辑  收藏  举报