做题记录整理树状数组1 P2163 [SHOI2007] 园丁的烦恼(2022/9/19)
首先看一张图(从洛谷题解里搞来的)

我们可以发现,要求矩形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;
}

浙公网安备 33010602011771号