1. 程式人生 > >HDU 5454 Excited Database 線段樹的維護

HDU 5454 Excited Database 線段樹的維護

Excited Database

Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 129    Accepted Submission(s): 26


Problem Description She says that any Pavarotti among the nightingales will serenade his mate while she sits on her eggs.
She says that any excited database can answer the queries efficiently.

You are given the two dimensional database as a matrix A
with n rows and n columns. In the beginning, A[i][j]=0 for all 1i,jn.
Then q operations or queries will be given in turn.

You should maintain the database for two type of operations:
1LR: for each element A[i][j] which satisfy Li+jR, increase the value to A[i][j]+1, where 2LR2n.
2LR: for each element A
[i][j]
which satisfy LijR, increase the value to A[i][j]+1, where 1nLRn1.
Meanwhile, you should answer the queries:
3x1x2y1y2: count the value of elements A[i][j] which satisfy x1ix2 and y1jy2, where 1x1<x2n and 1y1<y2n.
Input The input contains several test cases. The first line of the input is a single integert
which is the number of test cases. Then t test cases follow.

Each test case contains several lines. The first line contains the integer n and q.
The i-th line of the next q lines contains an operation 1LR" or 2LR", or a query 3x1x2y1y2".

The sum of n for all test cases would not be larger than 200000 and the sum of q would not be larger than 50000. Output For each test case, you should output answers to queries printed one per line. Sample Input 2 6 6 2 0 1 3 1 4 3 5 3 2 5 2 3 1 5 7 3 1 4 3 5 3 2 5 2 3 6 26 2 -4 -1 3 1 4 2 5 3 3 6 4 6 1 4 7 3 2 5 2 3 3 1 4 2 5 2 -3 -1 3 1 4 3 5 1 3 5 1 2 3 3 2 5 2 3 3 1 4 2 5 3 3 6 4 6 2 0 4 3 1 4 3 5 3 1 4 2 5 1 9 11 2 1 2 3 2 5 2 3 3 3 6 4 6 2 -2 2 1 7 12 3 1 4 3 5 3 2 5 2 3 3 1 4 2 5 3 3 6 4 6 Sample Output Case #1: 3 4 11 10 Case #2: 10 6 8 22 26 12 38 13 32 44 23 30 49 33 67 53 Source 題意:在一個n*n的矩陣中,(n<=20w),有兩種操作:操作1:將A[i]j](L<= i + j <=R)  +1,操作2:將A[i][j](L<=i - j < =R )   +1. 詢問x1,y1到x2,y2區域內的和。 思路:按照主對角線和副對角線分別建立線段樹,操作就是區間累加操作,維護需要維護區間的sum和A[i]*i的和,查詢是將矩形分解為2個等腰直角三角形和一個平行四邊形。分別進行詢問。 程式碼:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef __int64 LL;
const int maxn = 300005;
struct tree
{
	LL suml[maxn << 2], sumr[maxn << 2], sum[maxn << 2];
	LL add[maxn << 2];
	inline void pushup(int id, int L, int R)
	{
		LL mid = L + R >> 1;
		sum[id] = sum[id << 1] + sum[id << 1 | 1];
		suml[id] = suml[id << 1] + (mid - L + 1)*sum[id << 1 | 1] + suml[id << 1 | 1];
		sumr[id] = sumr[id << 1 | 1] + sumr[id << 1] + (R - mid)*sum[id << 1];
	}
	inline void pushdown(int id, int L, int R)
	{
		int mid = L + R >> 1;
		if (add[id])
		{
			LL ln = mid - L + 1;
			LL rn = R - mid;

			add[id << 1] += add[id];
			add[id << 1 | 1] += add[id];

			sum[id << 1] += add[id] * ln;
			sum[id << 1 | 1] += add[id] * rn;

			suml[id << 1] += add[id] * (1 + ln)*ln >> 1;
			suml[id << 1 | 1] += add[id] * (1 + rn)*rn >> 1;

			sumr[id << 1] += add[id] * (1 + ln)*ln >> 1;
			sumr[id << 1 | 1] += add[id] * (1 + rn)*rn >> 1;

			add[id] = 0;
		}
	}
	void build()
	{
		memset(sum, 0, sizeof(sum));
		memset(suml, 0, sizeof(suml));
		memset(sumr, 0, sizeof(sumr));
		memset(add, 0, sizeof(add));
	}
	LL queL(int id, int L, int R, int l, int r)
	{
		//  if(id>400000) while(1);
		if (l <= L&&R <= r) return (L - l)*sum[id] + suml[id];
		else
		{
			pushdown(id, L, R);
			int mid = L + R >> 1;
			LL res = 0;
			if (l <= mid) res += queL(id << 1, L, mid, l, r);
			if (mid<r) res += queL(id << 1 | 1, mid + 1, R, l, r);
			return res;
		}
	}
	LL queR(int id, int L, int R, int l, int r)
	{
		if (l <= L&&R <= r) return (r - R)*sum[id] + sumr[id];
		else
		{
			pushdown(id, L, R);
			int mid = L + R >> 1;
			LL res = 0;
			if (l <= mid) res += queR(id << 1, L, mid, l, r);
			if (mid<r) res += queR(id << 1 | 1, mid + 1, R, l, r);
			return res;
		}
	}
	LL que(int id, int L, int R, int l, int r)
	{
		if (l <= L&&R <= r) return sum[id];
		else
		{
			pushdown(id, L, R);
			int mid = L + R >> 1;
			LL res = 0;
			if (l <= mid) res += que(id << 1, L, mid, l, r);
			if (mid<r) res += que(id << 1 | 1, mid + 1, R, l, r);
			return res;
		}
	}
	void op(int id, int L, int R, int l, int r)
	{
		if (l <= L&&R <= r)
		{
			LL sn = R - L + 1;
			add[id]++;
			sum[id] += sn;
			suml[id] += (1 + sn)*sn >> 1;
			sumr[id] += (1 + sn)*sn >> 1;
		}
		else
		{
			pushdown(id, L, R);
			int mid = L + R >> 1;
			if (l <= mid) op(id << 1, L, mid, l, r);
			if (mid<r) op(id << 1 | 1, mid + 1, R, l, r);
			pushup(id, L, R);
		}
	}
}tz, tf;
int main()
{
	int T;
	scanf("%d", &T);
	int ks = 0;
	while (T--)
	{
		printf("Case #%d:\n", ++ks);
		tz.build();
		tf.build();
		int n, m;
		scanf("%d %d", &n, &m);
		while (m--)
		{
			int op;
			scanf("%d", &op);
			if (op == 1)
			{
				int l, r;
				scanf("%d %d", &l, &r);
				tf.op(1, 1, n << 1, l, r);
			}
			else if (op == 2)
			{
				int l, r;
				scanf("%d %d", &l, &r);
				l += n;
				r += n;
				tz.op(1, 1, n << 1, l, r);
			}
			else
			{
				int x1, y1, x2, y2;
				scanf("%d %d %d %d", &x1, &x2, &y1, &y2);
				LL ans = 0;
				int A, B, C, D;
				A = x1 - y1 + n;
				B = x1 - y2 + n;
				C = x2 - y2 + n;
				D = x2 - y1 + n;

				if (D >= max(A, C) + 1) ans += tz.queR(1, 1, n << 1, max(A, C) + 1, D);
				if (B <= min(A, C) - 1) ans += tz.queL(1, 1, n << 1, B, min(A, C) - 1);
				ans += tz.que(1, 1, n << 1, min(A, C), max(A, C))*(min(y2 - y1, x2 - x1) + 1);

				A = x1 + y1;
				B = x1 + y2;
				C = x2 + y2;
				D = x2 + y1;

				if (A <= min(B, D) - 1) ans += tf.queL(1, 1, n << 1, A, min(B, D) - 1);
				if (C >= max(B, D) + 1) ans += tf.queR(1, 1, n << 1, max(B, D) + 1, C);
				ans += tf.que(1, 1, n << 1, min(B, D), max(B, D))*(min(y2 - y1, x2 - x1) + 1);

				printf("%I64d\n", ans);
			}
		}
	}
	return 0;
}