题目一:给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的元素个数。
分析 :将数列分成sqrt(n)块,每块维护一个懒惰标记、一个有序表(vector实现)即可。
操作的时候,先暴力处理左右两端不完整的块,再处理中间完整的块,注意懒惰标记的释放。
区间加法O(√n),询问区间内小于某个值 x 的元素个数O(√n*log√n)
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 #define N 100005 13 using namespace std; 14 typedef long long ll; 15 int a[N],b[N]; 16 int mark[505]; 17 vector<int>vt[505]; 18 int n,blo; 19 void resort(int x) 20 { 21 vt[x].clear(); 22 for(int i=blo*(x-1)+1;i<=min(n,blo*x);i++) 23 vt[x].push_back(a[i]); 24 sort(vt[x].begin(),vt[x].end()); 25 } 26 int main() 27 { 28 29 cin>>n; 30 blo=sqrt(n); 31 for(int i=1;i<=n;i++) 32 scanf("%d",&a[i]); 33 for(int i=1;i<=n;i++) 34 { 35 b[i]=(i-1)/blo+1; 36 vt[b[i]].push_back(a[i]); 37 } 38 for(int i=1;i<=b[n];i++) 39 { 40 sort(vt[i].begin(),vt[i].end()); 41 } 42 for(int i=1;i<=n;i++) 43 { 44 int op,l,r,c; 45 scanf("%d%d%d%d",&op,&l,&r,&c); 46 if(op==0) 47 { 48 for(int i=l;i<=min(blo*b[l],r);i++) 49 a[i]+=c; 50 resort(b[l]); 51 for(int i=b[l]+1;i<=b[r]-1;i++) 52 { 53 mark[i]+=c; 54 } 55 if(b[l]!=b[r]) 56 { 57 for(int i=blo*(b[r]-1)+1;i<=r;i++) 58 a[i]+=c; 59 resort(b[r]); 60 } 61 } 62 else if(op==1) 63 { int num=0; 64 ll cc=c*c; 65 for(int i=l;i<=min(blo*b[l],r);i++) 66 if(cc>a[i]+mark[b[l]]) num++; 67 68 for(int i=b[l]+1;i<=b[r]-1;i++) 69 { 70 num+=lower_bound(vt[i].begin(),vt[i].end(),cc-mark[i])-vt[i].begin(); 71 } 72 73 if(b[l]!=b[r]) 74 { 75 for(int i=blo*(b[r]-1)+1;i<=r;i++) 76 if(cc>a[i]+mark[b[r]]) num++; 77 } 78 printf("%d ",num); 79 } 80 } 81 return 0; 82 }
题目二:给出一个长为 n 的数列,以及 n 个操作,操作涉及单点插入,单点询问,数据随机生成。
分析 :将数列分成sqrt(n)块,每块维护一个链表。由于单点插入会使原来的编号发生改变,所以每块还需维护好该块的区间(l,r)。
查找的时候先遍历找到属于哪个块,再在块中遍历即可,单次O(√n)。
一直插入操作可能使某个块过长,这时需要将其切成两个块(重构)
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 #include<list> 13 #define N 100005 14 using namespace std; 15 typedef long long ll; 16 int a[N]; 17 18 typedef struct NODE{ 19 int l, r; 20 list<int>lt; 21 }node; 22 list<node>head(405); 23 int main() 24 { 25 int n,blo; 26 cin>>n; 27 blo=sqrt(n); 28 for(int i=1;i<=n;i++) 29 scanf("%d",&a[i]); 30 int m=(n-1)/blo+1; 31 list<node>::iterator p=head.begin(); 32 for(int i=1;i<=m;i++) 33 { 34 p->l=(i-1)*blo+1; 35 p->r=min(n,i*blo); 36 for(int k=p->l;k<=p->r;k++) 37 { 38 p->lt.push_back(a[k]); 39 } 40 p++; 41 } 42 for(int i=1;i<=n;i++) 43 { 44 int op,l,r,c; 45 scanf("%d%d%d%d",&op,&l,&r,&c); 46 if(op==0) 47 { 48 p=head.begin(); 49 while(p!=head.end()) 50 { 51 if(p->l<=l&&l<=p->r) break; 52 p++; 53 } 54 int tot=0; 55 list<int>::iterator p2=p->lt.begin(); 56 while(p2!=p->lt.end()) 57 { 58 if(p->l+tot==l) {p->lt.insert(p2,r);break;} 59 p2++; 60 tot++; 61 } 62 p->r+=1; 63 p++; 64 for(;p!=head.end();p++) 65 { 66 p->l+=1,p->r+=1; 67 } 68 } 69 else if(op==1) 70 { 71 p=head.begin(); 72 while(p!=head.end()) 73 { 74 if(p->l<=r&&r<=p->r) break; 75 p++; 76 } 77 int tot=0; 78 list<int>::iterator p2=p->lt.begin(); 79 while(p2!=p->lt.end()) 80 { 81 if(p->l+tot==r) {printf("%d ",*p2);break;} 82 p2++; 83 tot++; 84 } 85 } 86 87 88 } 89 90 return 0; 91 }