Uva--12003(分块)
2015-04-29 11:46:41
题目:来自大白书的分块启蒙题... 题意:给出n,m,u,给出一串数A[1~n],有多个询问,每个询问要统计出L~R中比v小的A[i]个数k,并且将A[p]改成u×k/(R-L+1),让你求出最后的A[1~n]
思路:首先.. 用动态bst是可以做的,但是编程复杂度高。分块就完全可以优美地解决这道题。
将n个数分成sqrt(n)块,然后预处理出这sqrt(n)个块中的数并且排好序。
对于询问,如果L,R在同一块中就直接暴力,如果L,R不在同一块,暴力求出第一块和最后一块,中间的块因为已经预处理出各个有序块,所以直接二分求解个数。
对于修改,首先找到p位置在哪里块中,再找到其在该有序块中的位置,改变值后不断交换相邻元素使得块重新恢复有序。
时间复杂度:(1)预处理:O(sqrt(n)^2*log(sqrt(n))(2)询问:若同一块则是O(sqrt(n)),若不同块则是O(2*sqrt(n)+sqrt(n)) = O(sqrt(n)) (3)修改:O(sqrt(n))
从复杂度来看,分块非常实用,对于10^5级的数据查询很好用,而且常数也不大。。。(在实现莫队上,manhattan mst的复杂度虽然小,但常数真是... QAQ)
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i,n) for(int i=0;i<(n);++i) #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 300010; int n,m,u,size,L,R,v,p; int A[MAXN],bk[600][600]; int Query(){ int cnt = 0,lb = L / size,rb = R / size; if(lb == rb) //in the same block for(int i = L; i <= R; ++i) cnt += A[i] < v; else{ for(int i = L; i < (lb+1)*size; ++i) cnt += A[i] < v; //first for(int i = rb*size; i <= R; ++i) cnt += A[i] < v; //last for(int i = lb+1; i < rb; ++i) //midium 整块查询 cnt += lower_bound(bk[i],bk[i] + size,v) - bk[i]; } return cnt; } void Change(){ if(A[p] == v) return; int id = p / size; int pos = 0; while(bk[id][pos] != A[p]) pos++; A[p] = bk[id][pos] = v; while(pos + 1 < size && bk[id][pos] > bk[id][pos + 1]) swap(bk[id][pos],bk[id][pos + 1]),pos++; while(pos - 1 >= 0 && bk[id][pos] < bk[id][pos - 1]) swap(bk[id][pos],bk[id][pos - 1]),pos--; } int main(){ scanf("%d%d%d",&n,&m,&u); size = (int)sqrt(1.0 * n); int cur = 0,pos = 0; REP(i,n){ scanf("%d",A + i); bk[cur][pos++] = A[i]; if(pos == size){ pos = 0; cur++; } } REP(i,cur) sort(bk[i],bk[i] + size); if(pos) sort(bk[cur],bk[cur] + pos); REP(i,m){ scanf("%d%d%d%d",&L,&R,&v,&p); --L,--R,--p; int cnt = Query(); //printf("cnt : %d\n",cnt); v = (int)((ll)u * cnt / (R - L + 1)); //printf("v : %d\n",v); Change(); } REP(i,n) printf("%d\n",A[i]); return 0; }