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