【NOIP2014模拟10.25A组】画矩形

题目

这里写图片描述

分析

由于要求按时间顺序来操作,考虑整体二分:
对于一段二分出来的区间,将左区间的修改和右区间的查询取出来,每次更新每个查询的答案,正确性显然。
现在有一对修改和查询的操作(保证所有的查询都在修改之后),按x坐标排序,将矩形拆成左右两条线,用扫描线,树状数组维护,更新答案。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=200005;
using namespace std;
struct ddx
{
	int be,k,x,x1,y1,v;
}d[N];
int n,re[N][8],ans[N],sum[N+N],tot;
bool cmp(ddx x,ddx y)
{
	if(x.x!=y.x)
		return x.x<y.x;
	else 
		return x.k<y.k;
}
int to(int x)
{
	return x&-x;
}
int add(int x,int v)
{
	x+=2;
	while(x<=N)
	{
		sum[x]+=v;
		x+=to(x);
	}
}
int find(int x)
{
	x+=2;
	int num=0;
	while(x)
	{
		num+=sum[x];
		x-=to(x);
	}
	return num;
}
int dg(int l,int r)
{
	if(l==r) return 0;
	int mid=(l+r)/2;
	dg(l,mid);
	dg(mid+1,r);
	tot=0;
	for(int i=l;i<=mid;i++)
		if(!re[i][0])
		{
			d[++tot].x=re[i][1];
			d[tot].x1=re[i][2];
			d[tot].y1=re[i][4];
			d[tot].k=0;
			d[tot].v=1;
			d[tot].be=i;
			d[++tot].x=re[i][3];
			d[tot].x1=re[i][2];
			d[tot].y1=re[i][4];
			d[tot].k=2;
			d[tot].v=-1;
			d[tot].be=i;
		}
	for(int i=mid+1;i<=r;i++)
		if(re[i][0])
		{
			d[++tot].k=1;
			d[tot].x=re[i][1];
			d[tot].x1=re[i][2];
			d[tot].be=i;
		}
	sort(d+1,d+1+tot,cmp);
	for(int i=1;i<=tot;i++)
	{
		if(!d[i].k)
		{
			add(d[i].x1,d[i].v);
			add(d[i].y1+1,-d[i].v);
		}
		else
		if(d[i].k==2)
		{
			add(d[i].x1,d[i].v);
			add(d[i].y1+1,-d[i].v);
		}
		else
			ans[d[i].be]+=find(d[i].x1);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=2;j++) scanf("%d",&re[i][j]);
		if(!re[i][0]) scanf("%d%d",&re[i][3],&re[i][4]);
	}
	dg(1,n);
	for(int i=1;i<=n;i++)
		if(re[i][0])
			printf("%d
",ans[i]);
}
原文地址:https://www.cnblogs.com/chen1352/p/9071414.html