BZOJ3343

3343: 教主的魔法

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1038  Solved: 454
[Submit][Status][Discuss]

Description

教主最近學會了一種神奇的魔法,能夠使人長高。於是他準備演示給XMYZ信息組每個英雄看。於是N個英雄們又一次聚集在了一起,這次他們排成了一列,被編號爲1、2、……、N
每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間[LR](1≤LRN)內的英雄的身高全部加上一個整數W。(雖然L=R時並不符合區間的書寫規範,但我們可以認爲是單獨增加第LR)個英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,於是他們有時候會問WD閉區間 [LR] 內有多少英雄身高大於等於C,以驗證教主的魔法是否真的有效。
WD巨懶,於是他把這個回答的任務交給了你。
 

Input

       第1行爲兩個整數NQQ爲問題數與教主的施法數總和。
       第2行有N個正整數,第i個數代表第i個英雄的身高。
       第3到第Q+2行每行有一個操作:
(1)       若第一個字母爲“M”,則緊接着有三個數字LRW。表示對閉區間 [LR] 內所有英雄的身高加上W
(2)       若第一個字母爲“A”,則緊接着有三個數字LRC。詢問閉區間 [LR] 內有多少英雄的身高大於等於C
 

Output

       對每個“A”詢問輸出一行,僅含一個整數,表示閉區間 [LR] 內身高大於等於C的英雄數。
 

Sample Input

5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4

Sample Output

2
3

HINT

【輸入輸出樣例說明】

原先5個英雄身高爲1、2、3、4、5,此時[1, 5]間有2個英雄的身高大於等於4。教主施法後變爲1、2、4、5、6,此時[1, 5]間有3個英雄的身高大於等於4。

 

【數據範圍】

對30%的數據,N≤1000,Q≤1000。

對100%的數據,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。

Source

[Submit][Status][Discuss]


分塊是門大學問,,GG
對於每個塊,維護其塊內數字有序
每個修改操作,中間的塊打上標記,兩邊的塊暴力修改+塊重建
每個詢問操作,中間的塊二分答案,兩邊的塊暴力找
O(Q根號nlog根號n)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1000005;
const int MAXM = 1005;
char c[5];
int a[MAXN], i, j, n, k, m, block[MAXM][MAXM], cnt[MAXM], x, y, w, ans;
inline int get()
{
	char c;
	while ((c = getchar()) < 48 || c > 57);
	int res = c - 48;
	while ((c = getchar()) >= 48 && c <= 57)
		res = res * 10 + c - 48;
	return res;
}
int main()
{
	cin >> n >> m;
	for(i = 1; i <= n; i ++)
		a[i] = get();
	int nn = sqrt(n);
	nn += (n % nn != 0);
	for(i = 1; i <= nn; i ++)
	{
		for(j = (i - 1) * nn + 1, k = 1; j <= i * nn; j ++, k ++)
			block[i][k] = a[j];
		sort(block[i] + 1, block[i] + nn + 1);
	}
	for(i = 1; i <= m; i ++)
	{
		scanf("%s", c);
		x = get(); y = get(); w = get();
		if (x > y) swap(x, y);
		int bx = x / nn + (x % nn != 0);
		int by = y / nn + (y % nn != 0);
		if (c[0] == 'M')
		{
			if (bx == by)
			{
				for(j = x; j <= y; j ++)
					a[j] += w;
				k = 1;
				for(j = (bx - 1) * nn + 1; j <= bx * nn; j ++, k ++)
					block[bx][k] = a[j];
				sort(block[bx] + 1, block[bx] + 1 + nn);
				continue;
			}
			if (bx < by - 1)
			{
				for(j = bx + 1; j <= by - 1; j ++)
					cnt[j] += w;
			}
			for(j = x; j <= bx * nn; j ++)
				a[j] += w;
			for(j = nn * (by - 1) + 1; j <= y; j ++)
				a[j] += w;
			k = 1;
			for(j = (bx - 1) * nn + 1; j <= nn * bx; j ++, k ++)
				block[bx][k] = a[j];
			k = 1;
			for(j = (by - 1) * nn + 1; j <= nn * by; j ++, k ++)
				block[by][k] = a[j];
			sort(block[bx] + 1, block[bx] + 1 + nn);
			sort(block[by] + 1, block[by] + 1 + nn);
		}
		else		
		{
			ans = 0;
			if (bx == by)
			{
				for(j = x; j <= y; j ++)
					ans += (a[j] + cnt[bx] >= w);
				printf("%d\n", ans);
				continue;
			}
			if (bx < by - 1)
			{
				for(j = bx + 1; j <= by - 1; j ++)
				{
					int c = w - cnt[j];
					int l = 1, r = nn;
					while (l != r - 1)
					{
						if (l == r) break;
						int mid = (l + r) >> 1;
						if (block[j][mid] >= c) r = mid;
						else l = mid;  
					}
					if (block[j][l] >= c) ans += nn - l + 1;
					else if (block[j][r] >= c) ans += nn - r + 1;
				}
			}
			for(j = x; j <= bx * nn; j ++)
				ans += (a[j] + cnt[bx] >= w);
			for(j = (by - 1) * nn + 1; j <= y; j ++)
				ans += (a[j] + cnt[by] >= w);
			printf("%d\n", ans);
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章