#数列分块入门 2

这道题他们说不用分块就用平衡树,所以暴力拆解就用分块。

做了两道分块已经渐渐明白分块的一些模板在这里就放一下吧(用vector比用数组md方便多了)

 1 void /*修改操作*//*查询操作*/ (int l,int r.....,int val)/*修改的要素*/
 2 {
 3     /*总是先修改(查询)角区间,就是那种不是整块整块的*/
 4     for(int i=l;i<=(id[l],n)/*注意结束的区间可能就是 l~r 所以取min*/;i++) 
 5     {
 6         /*暴力枚举修改(查询)*/
 7     } 
 8     if(/* l 和 r 不在同一个区间 就把 r 所在的角区间枚举修改(查询)*/)
 9     {
10         /*暴力~*/
11         /*但是能二分或者别的什么能搞出来,那肯定换一下啦*/
12     }
13     /*最后就整块整块的枚举啦*/ 
14 } 

这道题就是维护每个块内的元素成单调的,这样最后查询的时候就可以用二分(lower_bound)来进行查询会快很多,而剩下的就只有暴力、暴力再暴力。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n;
 4 int block;
 5 int id[50009];
 6 int num[50009];
 7 int tag[10009];
 8 vector<int>v[10009];
 9 inline long long kd()
10 {
11     long long x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
14     return x*f;
15 }
16 inline void reset(int now)
17 {
18     int r=min(id[now]*block,n);
19     v[id[now]].clear();/*清空*/
20     for(int i=(id[now]-1)*block+1;i<=r;i++)v[id[i]].push_back(num[i]);/*挼进去*/
21     sort(v[id[now]].begin(),v[id[now]].end());/*排个序*/
22 }
23 inline void add(int l,int r,int c)
24 {
25     int minn=min(r,id[l]*block);
26     for(int i=l;i<=minn;i++)num[i]+=c;/*暴力修改角区间*/
27     reset(l);/*同下面reset的注释*/
28     if(id[l]!=id[r])/*如果 l 和 r 不在个区间之内*/
29     {
30         for(int i=(id[r]-1)*block+1;i<=r;i++)num[i]+=c;/*同样暴力*/
31         reset(r);/*角区间进行修改之后就打乱的顺序,所以重新排序*/
32     }
33     for(int i=id[l]+1;i<=id[r]-1;i++)tag[i]+=c;/*直接用tag来修改整块区间*/
34 }
35 int query(int l,int r,int c)
36 {
37     int ans=0;
38     int minn=min(r,id[l]*block);
39     for(int i=l;i<=minn;i++)
40         if(num[i]+tag[id[i]]<c)ans++;/*暴力枚举角区间*/
41     if(id[l]!=id[r])
42     {
43         for(int i=(id[r]-1)*block+1;i<=r;i++)
44         {
45             if(num[i]+tag[id[i]]<c)ans++;/*再次暴力枚举*/
46         }
47     }
48     for(int i=id[l]+1;i<=id[r]-1;i++)
49     {
50         int x=c-tag[i];
51         ans+=lower_bound(v[i].begin(),v[i].end(),x)-v[i].begin();/*整块的就直接二分查找*/
52     }
53     return ans;
54 }
55 int main()
56 {
57     n=kd();
58     for(int i=1;i<=n;i++)num[i]=kd();
59     block=(int)sqrt(n);
60     for(int i=1;i<=n;i++)
61     {
62         id[i]=(i-1)/block+1;
63         v[id[i]].push_back(num[i]);
64     }
65     for(int i=1;i<=id[n];i++)
66         sort(v[i].begin(),v[i].end());
67     for(int i=1;i<=n;i++)
68     {
69         int opt=kd();
70         int l=kd(),r=kd(),c=kd();
71         if(opt==0)add(l,r,c);
72         if(opt==1)cout<<query(l,r,c*c)<<endl;
73     }
74     return 0;
75 }

猜你喜欢

转载自www.cnblogs.com/1129-tangqiyuan/p/11779879.html