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;
}

 

posted @ 2015-04-29 12:00  Naturain  阅读(150)  评论(0编辑  收藏  举报