线段树模板二

发布时间 2023-07-26 14:37:45作者: 清初

1:扫描线+树状数组

题意

平面上有n个点(xi,yi)。回答q个询问,每个询问给定一个矩形[X1,X2]×[Y1,Y2],询问矩形里面有多少个点。

输入格式

第一行两个整数n,q(1≤n,q≤2×105)。
接下来n行,每行两个整数xi,yi(1≤xi,yi≤109)。
接下来q行,每行四个整数X1,X2,Y1,Y2(1≤X1≤X2≤109,1≤Y1≤Y2≤109)。

输出格式

对于每组询问,输出一个数表示答案。

样例输入

5 5
1 3
2 5
3 2
4 4
5 1
1 5 1 5
2 4 3 5
1 3 2 5
100 100 100 100
1 1 3 3

样例输出

5
2
3
0
1

点击查看代码
#include <bits/stdc++.h>

using namespace std;
#define int long long 

const int N = 1e6 + 10;
int n,m,k;
struct now{
	int a;
	int b;
	int c;
	int d;
};
vector<now>seg;
bool cmp(now l, now r)//排序注意点
{
	if(l.a==r.a)
	return l.c < r.c;
	return l.a < r.a;
}
int num[N],cnt[N];
void modify(int l,int r)
{
	for(;l <= k;)
	{
		num[l]+=r;
		l += (l&-l);
	}
}
int query(int l)
{
	int r = 0;
	for(;l;)
	{
		r += num[l];
		l -= (l&-l);
	}
	return r;
}
void solve()
{
	cin >> n >> m;
	vector<int> ans;
	for(int i = 1;i <= n;i ++)
	{
		int x,y;
		cin >> x >> y;
		seg.push_back({y,x,0,0});
		ans.push_back(x);
	}
	for(int i = 1;i <= m;i ++)
	{
		int x,y,xx,yy;
		cin >> x >> xx >> y >> yy;
		seg.push_back({yy,xx,1,i});
		seg.push_back({y-1,x-1,1,i});
		seg.push_back({y-1,xx,2,i});
		seg.push_back({yy,x-1,2,i});
	}
	sort(seg.begin(),seg.end(),cmp);
	sort(ans.begin(),ans.end());
	ans.erase(unique(ans.begin(),ans.end()),ans.end());
	k = seg.size();
	for(int i = 0;i < seg.size();i ++)
	{
		if(seg[i].c == 0)
		{
			int pos = lower_bound(ans.begin(),ans.end(),seg[i].b)-ans.begin()+1;
			modify(pos,1);//统计前缀和
		}
		else
		{
			int pos = upper_bound(ans.begin(),ans.end(),seg[i].b)-ans.begin();
			int res = query(pos);
			if(seg[i].c==1)
			cnt[seg[i].d]+=res;
			else
			cnt[seg[i].d]-=res;
		}
	}
	for(int i = 1;i <= n;i ++)
	cout << cnt[i] << '\n';
}
signed main()
{
	int tt = 1;
	//sc(tt);
	while(tt--)
	{
		solve();
	}
}