UVA 12003 Array Transformer [分块]

Array Transformer
Time Limit: 5000MS 64bit IO Format: %lld & %llu

Description
Write a program to transform an array A[1], A[2], … , A[n] according to m instructions. Each instruction
(L, R, v, p) means: First, calculate how many numbers from A[L] to A[R] (inclusive) are strictly less
than v, call this answer k. Then, change the value of A[p] to u ∗ k/(R − L + 1), here we use integer
division (i.e. ignoring fractional part).

Input
The first line of input contains three integer n, m, u (1 ≤ n ≤ 300, 000, 1 ≤ m ≤ 50, 000, 1 ≤ u ≤1, 000, 000, 000). Each of the next n lines contains an integer A[i] (1 ≤ A[i] ≤ u). Each of the nextm lines contains an instruction consisting of four integers L, R, v, p (1 ≤ L ≤ R ≤ n, 1 ≤ v ≤ u,1 ≤ p ≤ n).

Output
Print n lines, one for each integer, the final array.

Sample Input
10 1 11
1
2
3
4
5
6
7
8
9
10
2 8 6 10

Sample Output
1
2
3
4
5
6
7
8
9
6

Explanation: There is only one instruction: L = 2, R = 8, v = 6, p = 10. There are 4 numbers(2,3,4,5) less than 6, so k = 4. The new number in A[10] is 11 ∗ 4/(8 − 2 + 1) = 44/7 = 6.


如果写成树套树。。多此一举,因为查询和修改的操作都很简单。。
那么分块的话,每一块大小限制在 sqrt(n) 那么一开始块里面从小到大排序 时间复杂度为 O(sqrt^2(n) log(sqrt(n)) ),查询时在同一块为O(sqrt(n)),不在为 O(2sqrt(n)+sqrt(n)) = O(sqrt(n)) ,修改就暴力修改加一个伪冒泡就好了,同样O(sqrt(n))
整体复杂度对于n<=300000轻松解决。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 565;
typedef long long LL;
struct Block
{
    int size;
    LL a[maxn];
    void make_order()
    {
        sort(a+1,a+size+1);
    }
    void change(LL last,LL key) // erase first !! not positional modifying
    {
        int pos = lower_bound(a+1,a+size+1,last) - a;
        a[pos] = key;
        while(pos>1 && a[pos-1] > a[pos]) swap(a[pos-1],a[pos]),pos--;
        while(pos<size && a[pos] > a[pos+1]) swap(a[pos],a[pos+1]),pos++;
    }
    int rank(LL key)
    {
        return lower_bound(a+1,a+size+1,key)-a-1;
    }
    void print()
    {
        for(int i=1;i<=size;i++) printf(AUTO"\n",a[i]);
    }
}block[maxn];
int maxblock,cap;
inline int idx(int pos) { return (pos-1)/cap+1; }
LL arr[maxn*maxn];
int n,m;
LL u;
void init()
{
    scanf("%d%d"AUTO,&n,&m,&u);
    cap = floor(sqrt(n+0.1));
    maxblock=1;
    for(int i=1;i<=n;i++)
    {
        scanf(AUTO,arr+i);
        block[maxblock].a[++block[maxblock].size] = arr[i];
        if(block[maxblock].size == cap) maxblock++;
    }
    if(!block[maxblock].size) maxblock--;
    for(int i=1;i<=maxblock;i++) block[i].make_order();
}
int query(int l,int r,LL key)
{
    int ret = 0;
    if(idx(l) == idx(r))
    {
        for(int i=l;i<=r;i++) ret += arr[i]<key;
        return ret;
    }
    for(int i=l;i<=idx(l)*cap;i++) ret += arr[i]<key;
    for(int i=(idx(r)-1)*cap+1;i<=r;i++) ret += arr[i]<key;
    for(int i=idx(l)+1;i<=idx(r)-1;i++) ret += block[i].rank(key);
    return ret;
}
void modify(int pos,LL key)
{
    int id = idx(pos);
    block[id].change(arr[pos],key);
    arr[pos] = key; // !!
}
int main()
{
    freopen("block.in","r",stdin);
    freopen("block.out","w",stdout);
    init();
    for(int i=1;i<=m;i++)
    {
        int l,r,p;
        LL v;
        scanf("%d%d"AUTO"%d",&l,&r,&v,&p);
        int k = query(l,r,v);
        modify(p,u*k/(r-l+1));
    }
    for(int i=1;i<=n;i++) printf(AUTO"\n",arr[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值