HDU - 1166 敌兵布阵 (CDQ分治解法)

这道题线段树,树状数组,带修改莫队都能解,这里用CDQ分治解,当做学习CDQ分治!


CDQ分治刚开始学可能会有点困难,但是当你做题的时候,再去体会,就会有感觉了。

最主要来说,CDQ还是拿来降维用的,很多篇博客都有谈到,实际上,求逆序数的分治解法,就是CDQ分治的核心问题。分治分成左右两个区间的时候,左边的区间是如何影响右边区间的,只要我们把这个问题解决,那么就可以用CDQ分治解决。

比如这道题,我们把所有的查询拆开,拆成查询前缀和。那么很明显,当修改的坐标小于查询的坐标的时候,这个修改就会影响后面的查询,那么我就要修改,然后再做那个查询。具体的话要看代码去体会了。


#include 
using namespace std;
typedef long long int ll;

struct Query
{
	int type;
	int id;
	int val;
	bool operator<(const Query &b) const
	{
		if (id == b.id)
			return type < b.type;
		return id < b.id;
	}
} q[200005];
int qn;

int ans[200005];
int an;

Query tmp[200005];
void CDQ(int l, int r)
{
	if (r <= l + 1)
		return;
	int m = (l + r) / 2;
	CDQ(l, m);
	CDQ(m, r);
	int sum = 0;
	int i = l, j = m, k = 0;
	while (i < m && j < r)
	{
		if (q[i] < q[j])
		{
			if (q[i].type == 1)
				sum += q[i].val;
			tmp[k++] = q[i++];
		}
		else
		{
			if (q[j].type == 2)
				ans[q[j].val] -= sum;
			else if (q[j].type == 3)
				ans[q[j].val] += sum;
			tmp[k++] = q[j++];
		}
	}

	while (i < m)
		tmp[k++] = q[i++];
	while (j < r)
	{
		if (q[j].type == 2)
			ans[q[j].val] -= sum;
		else if (q[j].type == 3)
			ans[q[j].val] += sum;
		tmp[k++] = q[j++];
	}
	for (int i = 0; i < k; i++)
		q[i + l] = tmp[i];
}

char str[200];
int main()
{
	int T;
	scanf("%d", &T);
	int N;
	int ttt=1;
	while (T--)
	{
		memset(ans,0,sizeof(ans));
		qn=0;
		an=0;
		printf("Case %d:\n",ttt++);
		scanf("%d", &N);
		for (int i = 1; i <= N; i++)
		{
			q[qn].id = i;
			q[qn].type = 1;
			scanf("%d", &q[qn].val);
			qn++;
		}

		while(1){
			
			scanf("%s", str);
			if(str[0]=='E')
				break;
			if(str[0]=='A'){
				q[qn].type = 1;
				scanf("%d%d", &q[qn].id, &q[qn].val);
			}
			else if(str[0]=='S'){
				q[qn].type = 1;
				scanf("%d%d", &q[qn].id, &q[qn].val);
				q[qn].val=-q[qn].val;
			}
				
			else if(str[0]=='Q')
			{
				int l, r;
				scanf("%d%d", &l, &r);
				q[qn].type=2;
				q[qn].id = l - 1;
				q[qn].val = an;
				qn++;
				q[qn].type = 3;
				q[qn].id = r;
				q[qn].val = an;
				an++;
			}
			qn++;
		}


		CDQ(0, qn);
		for (int i = 0; i < an; i++)
			printf("%d\n", ans[i]);
			
	}

	return 0;
}

你可能感兴趣的:(————ACM相关————,——算法技巧——,ACM,-,CDQ分治)