离线二维数点

【模板】离线二维数点 新板子。

本质就是:前缀和,利用排序后逐个插入实现区间统计。

例如当统计 \([1,l]\) 时,\([l+1,r]\) 的所有数还没有被插入,所以不会影响答案。

#include<bits/stdc++.h>
using namespace std;
int n,m,tot=0,V=2e6+10;
//bizy AK NGOI
const int maxn=2e6+10;
int a[maxn],ans[maxn];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x << 1) + (x << 3)+ch-48;ch=getchar();}
	return x*f;
}
inline void write(int x) {
	static int sta[35];
	int top=0;
	do{sta[top++]=x%10,x/=10;}while(x);
	while(top) putchar(sta[--top]+48);
}
struct node{
	int l,r,sum;
}t[maxn*4];
#define ls id<<1
#define rs id<<1|1
void up(int id){t[id].sum=t[ls].sum+t[rs].sum;}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		t[id].sum=0;//后面要逐个插入
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	up(id);
}
void add(int id,int x){
	if(t[id].r<x||t[id].l>x)return;
	if(t[id].l==t[id].r&&t[id].l==x){
		t[id].sum++;
		return;
	}
	add(ls,x),add(rs,x);
	up(id);
}
int query(int id,int l,int r){
	if(t[id].r<l||t[id].l>r)return 0;
	if(l<=t[id].l&&t[id].r<=r)return t[id].sum;
	return query(ls,l,r)+query(rs,l,r);
}
struct qry{
	int r,type,x,id;
	friend bool operator<(qry aa,qry bb){
		return aa.r<bb.r;
	}
}b[maxn*2];
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++){
		int l=read(),r=read(),x=read();
		b[++tot]={l-1,-1,x,i};//[1,l-1]
		b[++tot]={r,1,x,i};//[1,r]
	}
	int k=1;
	sort(b+1,b+tot+1);
	build(1,1,V);
	for(int i=1;i<=tot;i++){
		while(k<=b[i].r)add(1,a[k++]);//新建节点,注意不是++k
		ans[b[i].id]+=b[i].type*query(1,1,b[i].x);//ans=[1,r]-[1,l-1]
	}
	for(int i=1;i<=m;i++)write(ans[i]),puts("");
	return 0;
} 

我发现使用 Treap 会 TLE

#include<bits/stdc++.h>
using namespace std;
int n,m,tot=0,V=2e6+10;
//bizy AK NGOI
const int maxn=2e6+10;
int a[maxn],ans[maxn];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x << 1) + (x << 3)+ch-48;ch=getchar();}
	return x*f;
}
inline void write(int x) {
	static int sta[35];
	int top=0;
	do{sta[top++]=x%10,x/=10;}while(x);
	while(top) putchar(sta[--top]+48);
}
int root=0,k;
struct treap{
	int ls,rs;
	int val,pri;
	int cnt,size;
}t[maxn];
void up(int id){t[id].size=t[t[id].ls].size+t[t[id].rs].size+t[id].cnt;}
void zag(int &rt){//左旋
	int b=t[rt].rs;
	t[rt].rs=t[b].ls;
	t[b].ls=rt;
	up(rt);up(b);
	rt=b;
}
void zig(int &rt){//右旋
	int b=t[rt].ls;
	t[rt].ls=t[b].rs;
	t[b].rs=rt;
	up(rt);up(b);
	rt=b;
}
void insert(int &rt,int x){
	if(rt==0){
		t[++k].val=x;
		t[k].cnt=t[k].size=1;
		t[k].pri=rand()%1145140;
		rt=k;
		return;
	}
	t[rt].size++;
	if(x==t[rt].val){
		t[rt].cnt++;
		return;
	}
	if(x<t[rt].val){
		insert(t[rt].ls,x);
		if(t[t[rt].ls].pri<t[rt].pri)zig(rt);
	}
	else{
		insert(t[rt].rs,x);
		if(t[t[rt].rs].pri<t[rt].pri)zag(rt);
	}
}
int query(int rt,int x){
	if(rt==0)return 1;
	if(t[rt].val<=x)return t[t[rt].ls].size+t[rt].cnt+query(t[rt].rs,x);
	else return query(t[rt].ls,x);
}
struct qry{
	int r,type,x,id;
	friend bool operator<(qry aa,qry bb){
		return aa.r<bb.r;
	}
}b[maxn*2];
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++){
		int l=read(),r=read(),x=read();
		b[++tot]={l-1,-1,x,i};//[1,l-1]
		b[++tot]={r,1,x,i};//[1,r]
	}
	int k=1;
	sort(b+1,b+tot+1);
	for(int i=1;i<=tot;i++){
		while(k<=b[i].r)insert(root,a[k++]);//新建节点,注意不是++k
		ans[b[i].id]+=b[i].type*query(root,b[i].x);//ans=[1,r]-[1,l-1]
	}
	for(int i=1;i<=m;i++)write(ans[i]),puts("");
	return 0;
} 

P10728 [NOISG 2023 Qualification] Swords

没错,这个也可以用离线二维数点做。

就是查询 \((x,y)\)\((V,V)\) 中的点数是否为 1(要考虑自己)。

#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
const int maxn=3e6+10,V=3e6+10;//懒得改了,直接开大
int a[maxn],tot,tx,ty,tot2,ans[maxn];
struct tr{
	int x,y,id;
	friend bool operator<(tr aa,tr bb){
		return aa.x<bb.x;
	}
}v[maxn];
struct qry{
	int a,b,c,d,id;
}b[maxn];
struct qry2{
	int x,y,type,id;
	friend bool operator<(qry2 aa,qry2 bb){
		return aa.x<bb.x;
	}
}q[maxn*4];
int bx[maxn],by[maxn];
int getx(int x){return lower_bound(bx+1,bx+tx+1,x)-bx;}
int gety(int y){return lower_bound(by+1,by+ty+1,y)-by;}
struct node{
	int l,r,sum;
}t[maxn*4];
#define ls id<<1
#define rs id<<1|1
void up(int id){t[id].sum=t[ls].sum+t[rs].sum;}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		t[id].sum=0;//后面要逐个插入
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	up(id);
}
void add(int id,int x){
	if(t[id].r<x||t[id].l>x)return;
	if(t[id].l==t[id].r&&t[id].l==x){
		t[id].sum++;
		return;
	}
	add(ls,x),add(rs,x);
	up(id);
}
int query(int id,int l,int r){
	if(t[id].r<l||t[id].l>r)return 0;
	if(l<=t[id].l&&t[id].r<=r)return t[id].sum;
	return query(ls,l,r)+query(rs,l,r);
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	// freopen("point.in","r",stdin);
	// freopen("point.out","w",stdout);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		int x,y;
		cin>>x>>y;
		v[i]={x,y,i};
		bx[++tx]=x,by[++ty]=y;
	}
	for(int i=1;i<=n;i++){
		b[++tot]={v[i].x,v[i].y,V,V,i};
		bx[++tx]=0,bx[++tx]=v[i].x;
		by[++ty]=0,by[++ty]=v[i].y;
	}
	sort(bx+1,bx+tx+1);
	sort(by+1,by+ty+1);
	tx=unique(bx+1,bx+tx+1)-bx-1;
	ty=unique(by+1,by+ty+1)-by-1;
	for(int i=1;i<=n;i++)v[i]={getx(v[i].x),gety(v[i].y),v[i].id};
	for(int i=1;i<=n;i++)b[i]={getx(b[i].a),gety(b[i].b),getx(b[i].c),gety(b[i].d),b[i].id};
	build(1,1,V);
	int k=1;
	sort(v+1,v+n+1);
	for(int i=1;i<=n;i++)a[i]=v[i].y;
	for(int i=1;i<=n;i++){
		q[++tot2]={maxn,maxn,1,i};
		q[++tot2]={b[i].a-1,maxn,-1,i};
		q[++tot2]={maxn,b[i].b-1,-1,i};
		q[++tot2]={b[i].a-1,b[i].b-1,1,i};
	}
	sort(q+1,q+tot2+1);
	for(int i=1;i<=tot2;i++){
		while(v[k].x<=q[i].x&&k<=n)add(1,a[k++]);
		ans[q[i].id]+=q[i].type*query(1,1,q[i].y);
//		cout<<q[i].type*query(1,1,q[i].r)<<endl;
	}
	int cans=0;
	for(int i=1;i<=n;i++){if(ans[i]==1)cans++;}
	cout<<cans;
	return 0;
}

练习

posted @ 2025-12-07 10:17  zhangruixiang  阅读(5)  评论(0)    收藏  举报