做题记录整理树状数组1 P2163 [SHOI2007] 园丁的烦恼(2022/9/19)

P2163 [SHOI2007] 园丁的烦恼

首先看一张图(从洛谷题解里搞来的)

我们可以发现,要求矩形abcd里有几棵树本质上其实就是

f(c,d)-f(a-1,d)-f(c,b-1)+f(a-1,b-1)

的值,其中f(i,j)表示从(0,0)~(i,j)有多少棵树

所以最后就变成了一个二维偏序

然后我们就把一个问题拆开成4个问题,对他们进行排序,然后根据每次的询问把点加到树状数组里,最后再把问题汇总就ok了

#include<iostream>
#include<stdio.h>
#include<algorithm>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node {
	int x;
	int y;
} a[5000005];

struct node2 {
	int x;
	int y;
	int id;
} z[5000005];
int cnt;
int s[5000005*2],n,ans[5000005],m;
bool cmp(node x,node y) {
	return x.x<y.x;
}

bool cmp2(node2 x,node2 y) {
	return x.x<y.x;
}

int lb(int x) {
	return x&-x;
}
void xg(int x,int k) {
	x++;
	while(x<=5000005) {
		s[x]+=k;
		x+=lb(x);
	}
}

int cx(int x) {
	x++;
	int ans=0;
	while(x>0) {
		ans+=s[x];
		x-=lb(x);
	}
	return ans;
}
int main() {
	int x1,y1,x2,y2;
	cin>>n>>m;
	for1(i,1,n)
	scanf("%d%d",&a[i].x,&a[i].y);
	for1(i,1,m) {
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		cnt++;
		z[cnt]=(node2) {
			x2,y2,cnt
		};
		cnt++;
		z[cnt]=(node2) {
			x1-1,y2,cnt
		};
		cnt++;
		z[cnt]=(node2) {
			x2,y1-1,cnt
		};
		cnt++;
		z[cnt]=(node2) {
			x1-1,y1-1,cnt
		};
	}
	sort(a+1,a+n+1,cmp);
	sort(z+1,z+cnt+1,cmp2);
	int now=1;
	for1(i,1,cnt) {
		while(a[now].x<=z[i].x&&now<=n) {
			xg(a[now].y,1);
			now++;
		}
		ans[z[i].id]+=cx(z[i].y);
	}
	for(int i=1; i<=cnt; i+=4)
		printf("%d\n",ans[i]+ans[i+3]-ans[i+1]-ans[i+2]);
	return 0;
}
posted @ 2022-09-19 21:47  yyx525jia  阅读(34)  评论(0)    收藏  举报