bzoj1938 & 洛谷P2163 [SHOI2007] 园丁的烦恼 离散化+树状数组

题目链接:
bzoj1938
洛谷2163

题目大意:
给定一个矩阵,矩阵内有 n n n棵树,给出 m m m个询问,每次询问一个矩形里有多少棵树。
n , m &lt; = 5 ∗ 1 0 5 , x i , y i &lt; = 1 0 7 n,m&lt;=5*10^5,x_i,y_i&lt;=10^7 n,m<=5105,xi,yi<=107

本来以为要用 c d q cdq cdq分治,结果发现直接树状数组就珂以了……
把矩形中的树看成插入操作,就相当于在矩阵中 ( x , y ) (x,y) (x,y)的位置 + 1 +1 +1
然后把每个询问拆成二维前缀和的形式,则每个询问就变成查询左下角为 ( 1 , 1 ) (1,1) (1,1)、右上角为 ( x , y ) (x,y) (x,y)的矩形内有多少棵树。
离线,把所有插入操作和查询操作以 x x x坐标为第一关键字, y y y坐标为第二关键字排序,
那么若第 i i i个操作是询问操作,仅有 [ 1 , i − 1 ] [1,i-1] [1,i1]中的查询操作能影响到它,因为第 i i i个操作后面的操作 x x x坐标都 &gt; = x i &gt;=x_i >=xi(若 x j = x i , 则 y j &gt; y i x_j=x_i,则y_j&gt;y_i xj=xiyj>yi)。
同理,若第 i i i个操作是查询操作,那么它不会影响到 [ 1 , i − 1 ] [1,i-1] [1,i1]中的查询操作。
因此,对于每个询问操作,相当于求有多少个修改操作的 j j j满足 j &lt; i , y j &lt; y i j&lt;i,y_j&lt;yi j<i,yj<yi
发现这是个单点修改,区间查询,就硬上树状数组就珂以了qwq

代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#define re register int
#define rl register ll
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline void write(int x) {
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
inline char GetChar() {
	char ch=getchar();
	while(ch!='A' && ch!='B' && ch!='C')	ch=getchar();
	return ch;
}
namespace I_Love {

const int Size=500005;
int n,m,tot,maxn,ny[Size*5];
struct zyd {
	int id,x,y,k,dt;
} Q[Size*5];
inline void Push(int x,int y,int k,int id) {
	Q[++tot].x=x;
	Q[tot].y=y;
	Q[tot].k=k;
	Q[tot].id=id;
	Q[tot].dt=tot;
}
inline bool comp(zyd jzm,zyd xjp) {
	if(jzm.x!=xjp.x)	return jzm.x<xjp.x;
	if(jzm.y!=xjp.y)	return jzm.y<xjp.y;
	return jzm.dt<xjp.dt;
}
int tree[Size];
inline void update(int x) {
	for(re i=x; i<=maxn; i+=lowbit(i)) {
		tree[i]++;
	}
}
inline int query(int x) {
	int ans=0;
	for(re i=x; i; i-=lowbit(i)) {
		ans+=tree[i];
	}
	return ans;
}
int out[Size];
void Fujibayashi_Ryou() {
	n=read();
	m=read();
	for(re i=1; i<=n; i++) {
		int x=read();
		int y=read();
		Push(x,y,0,0);
	}
	for(re i=1; i<=m; i++) {
		int a=read();
		int b=read();
		int c=read();
		int d=read();
		Push(c,d,1,i);
		Push(a-1,b-1,1,i);
		Push(a-1,d,-1,i);
		Push(c,b-1,-1,i);
	}
	sort(Q+1,Q+1+tot,comp);
	for(re i=1; i<=tot; i++) {
		ny[i]=Q[i].y;
	}
	sort(ny+1,ny+1+tot);
	maxn=unique(ny+1,ny+1+tot)-(ny+1);
	for(re i=1; i<=tot; i++) {
		Q[i].y=lower_bound(ny+1,ny+1+maxn,Q[i].y)-ny;
	}
	for(re i=1; i<=tot; i++) {
		if(!Q[i].k) {
			update(Q[i].y);
		} else if(Q[i].k==1) {
			out[Q[i].id]+=query(Q[i].y);
		} else {
			out[Q[i].id]-=query(Q[i].y);
		}
	}
	for(re i=1; i<=m; i++) {
		printf("%d\n",out[i]);
	}
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值