【省選模擬】尋寶遊戲(掃描線)(點定位)

傳送門

  • 考慮將寶石和詢問點定位到唯一一個極小的包涵它的矩形,這個可以通過掃描線解決
    我的做法是考慮左邊第一個包涵它的矩陣,用線段樹維護,每個結點維護一個棧
    同時可以把矩形定位到唯一一個矩形

  • 在每個矩形中處理,我們需要減去兩個階梯形的東西

在這裏插入圖片描述

  • 考慮從後向前掃描線維護這個階梯,每遇到一個右邊界就將管轄區間 [l,r][l,r] 的全部放到 l1l-1,然後查詢是一個後綴區間查詢(不考慮下階梯),接下來的做法是最開始只考慮了右階梯假掉後產生的,設只考慮右階梯的答案爲 S1S_1,只考慮下階梯的答案是 S2S_2,兩個都不考慮的爲 SS,那麼簡單容斥,答案就是 S1+S2SS_1+S_2-S,處理下階梯按 yy 掃描線即可
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define fi first
#define se second
using namespace std;
namespace IO{
	cs int Rlen=1<<22|1;
	inline char gc(){
		static char buf[Rlen], *p1, *p2;
		(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
		return p1==p2?EOF:*p1++;
	}
	int read(){
		int x=0; char c=gc(); bool f=false;
		while(!isdigit(c)) f=c=='-', c=gc();
		while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
		return f?-x:x; 
	}
} using namespace IO;
cs int N = 2e5 + 50;
cs int A = 1e6;
typedef pair<int, int> pi;
struct pnt{ 
	int x, y, c, blk, dn; 
	bool operator < (cs pnt &a) cs{ 
	return x<a.x||(x==a.x&&y<a.y); } 
};
struct box{ 
	int x, l, r, c; 
	bool operator < (cs box &a) cs{ 
	return x<a.x||(x==a.x&&l<a.l); } 
};
struct mem{ int x, y, l, r; };
mem bin[N];
int blk[N];
int n, m, q, as[N];
pnt a[N], b[N];
box c[N<<1]; int ct;
struct atom{ int opt, c, x, l, r; };
vector<atom> S[N];
vector<atom> T[N];
namespace zkw{
	cs int N = 1 << 20;
	vector<pi> S[N<<1];
	void ins(int l, int r, int v, int c){
		for(l+=N-1,r+=N+1; l^r^1; l>>=1,r>>=1){
			if(l&1^1) S[l^1].pb(pi(v,c));
			if(r&1) S[r^1].pb(pi(v,c));
		}
	} 
	void pop(int l, int r){
		for(l+=N-1,r+=N+1; l^r^1; l>>=1,r>>=1){
			if(l&1^1) S[l^1].pop_back();
			if(r&1) S[r^1].pop_back();
		}
	}
	int qry(int x){
		int v=-1, c=0; 
		for(x+=N; x; x>>=1){
			if(!S[x].empty() && S[x].back().fi > v)
			v = S[x].back().fi, c = S[x].back().se;
		} return c;
	}
}
void pre_work(pnt *a, int n){
	for(int l=1,r=1,j=0; l<=ct; l=r){
		while(c[r].x == c[l].x){
			if(c[r].c > 0){
				if(!blk[c[r].c]) blk[c[r].c] = zkw :: qry(c[r].l);
				zkw :: ins(c[r].l,c[r].r,c[r].x,c[r].c);
			} else zkw :: pop(c[r].l,c[r].r); ++r;
		} while(j < n && a[j+1].x < c[r].x) ++j, a[j].blk = zkw :: qry(a[j].y);
	}
}
struct cp{ 
	int x, c; cp(int _x=0, int _c=0){ x=_x; c=_c; }
	bool operator < (cs cp &a) cs{ return x < a.x || (x == a.x && c < a.c); }; 
};
void sub_work(pnt *a, int n){ // work for down 
	static multiset<cp> St;
	for(int l=1,r=1,j=0; l<=ct; l=r){
		while(c[r].x == c[l].x){
			if(c[r].c > 0) St.insert(cp(c[r].r+1,c[r].c)), St.insert(cp(c[r].l,c[r].c));
			else St.erase(St.find(cp(c[r].r+1,-c[r].c))), St.erase(St.find(cp(c[r].l,-c[r].c))); ++r;
		}
		while(j < n && a[j+1].x < c[r].x){
			++j; auto t = St.upper_bound(cp(a[j].y,0));
			assert(t != St.end());
			a[j].dn = t->c;
		}
	}
}
namespace SGT{
	cs int N = A << 2;
	#define mid ((l+r)>>1)
	bool c[N]; int sm[N];
	void pushup(int x){ sm[x] = sm[x<<1] + sm[x<<1|1]; }
	void cov(int x){ c[x] = true; sm[x] = 0; }
	void down(int x){ if(c[x]) cov(x<<1), cov(x<<1|1), c[x]=0; }
	void ins(int x, int l, int r, int p, int v){
		if(p > A) return; if(l==r) return sm[x]+=v,void(); down(x);
		(p<=mid) ? ins(x<<1,l,mid,p,v) : ins(x<<1|1,mid+1,r,p,v);
		pushup(x);
	}
	void mdf(int x, int l, int r, int L, int R){
		if(L<=l&&r<=R) return cov(x),void(); down(x);
		if(L<=mid) mdf(x<<1,l,mid,L,R);
		if(R>mid) mdf(x<<1|1,mid+1,r,L,R); pushup(x);
	} 
	int qry(int x, int l, int r, int L, int R){
		if(L<=l&&r<=R) return sm[x]; down(x); int as=0;
		if(L<=mid) as+=qry(x<<1,l,mid,L,R);
		if(R>mid) as+=qry(x<<1|1,mid+1,r,L,R); return as;
	}
}
void work(vector<atom> &S){
	sort(S.begin(),S.end(),[](cs atom &a, cs atom &b){
		return a.x > b.x || (a.x == b.x && a.opt < b.opt);
	}); SGT::cov(1);
	for(auto t : S){
		if(t.opt == 0){
			int Sm = SGT::qry(1,1,A,t.l,t.r); 
			SGT::mdf(1,1,A,t.l,t.r); if(t.l>1) SGT::ins(1,1,A,t.l-1,Sm);
		}
		if(t.opt == 1) SGT::ins(1,1,A,t.l,1);
		if(t.opt == 2) as[t.c] += SGT::qry(1,1,A,t.l,A);//, cout<<t.c<<" "<<as[t.c]<<endl;
	} S.clear();
}
void dec_work(vector<atom> &S){
	sort(S.begin(),S.end(),[](cs atom &a, cs atom &b){
		return a.x > b.x || (a.x == b.x && a.opt < b.opt);
	}); SGT::cov(1);
	for(auto t : S){
		if(t.opt == 1) SGT::ins(1,1,A,t.l,1);
		if(t.opt == 2) as[t.c] -= SGT::qry(1,1,A,t.l,A);//, cout << t.c<<" "<<as[t.c] << endl;
	} //S.clear();
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
//	freopen("my.out","w",stdout);
	#endif
	n=read();
	for(int i=1,x,y,l,r; i<=n; i++){
		l=read(), x=read(), r=read(), y=read();
		c[++ct] = (box){x,l,r,i}; c[++ct] = (box){y+1,l,r,-i};
		bin[i]=(mem){x,y,l,r};
//		cout<<x<<" "<<l<<" "<<r<<endl;
	} ++n; c[++ct] = (box){0,1,A,n}; c[++ct] = (box){A+1,1,A,-n};
	m=read(); for(int i=1; i<=m; i++) a[i]=(pnt){read(),read()},swap(a[i].x,a[i].y);
	q=read(); for(int i=1; i<=q; i++) b[i]=(pnt){read(),read(),i},swap(b[i].x,b[i].y);
	sort(c+1, c+ct+1);
	sort(a+1, a+m+1);
	sort(b+1, b+q+1);
	pre_work(a,m);
	pre_work(b,q);
	sub_work(b,q);
//	for(int i=1; i<=n; i++) cout<<b[i].blk<<endl;
	for(int i=1; i<=m; i++)
	S[a[i].blk].pb({1,0,a[i].x,a[i].y,0});
	for(int i=1; i<=q; i++)
	S[b[i].blk].pb({2,b[i].c,b[i].x,b[i].y,0});
	for(int i=1; i<=ct; i++) if(c[i].c<0 && blk[-c[i].c])
	S[blk[-c[i].c]].pb({0,0,c[i].x-1,c[i].l,c[i].r});
	for(int i=1; i<=n; i++) if(!S[i].empty()) work(S[i]);
	
//	for(int i=1; i<=q; i++) cout<<b[i].dn<<endl;
	for(int i=1; i<=m; i++)
	S[a[i].blk].pb({1,0,a[i].y,a[i].x,0});
	for(int i=1; i<=q; i++) 
	S[b[i].blk].pb({2,b[i].c,b[i].y,b[i].x,0});
	for(int i=1; i<=n; i++) if(blk[i])
	S[blk[i]].pb({0,i,bin[i].r,bin[i].x,bin[i].y});
	for(int i=1; i<=n; i++) if(!S[i].empty()) dec_work(S[i]), work(S[i]);
	for(int i=1; i<=q; i++) cout<<as[i]<<'\n';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章