线段树/树状数组维护二维偏序的trick

在我们要维护形如\(x_i>x_j\land y_i>y_j\)(或\(x_i\ge x_j\land y_i\ge y_j\))的条件时,可以将所有\((x_i,y_i)\)以x为第一关键字,y为第二关键字进行排序。那么在顺序处理时,\(x_i>x_j\)已经满足,只需满足\(y_i>y_j\),则可用线段树或树状数组维护。

例题:「POI2005」AUT-The Bus

#include <bits/stdc++.h> 
using namespace std;
struct segetree {
	int l,r,tmp1,tmp2;
	long long tmp3;
	struct segenode {
		segenode *ls,*rs;
		long long v;
		segenode() {ls=rs=NULL,v=0;}
	} Root;
	void edi(segenode *k,const int l,const int r) {
		if (l==r) return void(k->v=tmp3);
		if (tmp1<=(l+r)/2)
			edi((k->ls?k->ls:(k->ls=new segenode)),l,(l+r)/2);
		else edi((k->rs?k->rs:(k->rs=new segenode)),(l+r)/2+1,r);
		k->v=max((k->ls?k->ls->v:0),(k->rs?k->rs->v:0));
	}
	long long gs(segenode *k,const int l,const int r) {
		if (tmp1>r||tmp2<l) return 0;
		if (tmp1<=l&&r<=tmp2) return k->v;
		return max((k->ls?gs(k->ls,l,(l+r)/2):0),
		(k->rs?gs(k->rs,(l+r)/2+1,r):0));
	}
	segetree(const int l=0,const int r=0):l(l),r(r) {}
	inline void edi(const int p,const long long v) {
		tmp1=p,tmp3=v; edi(&Root,l,r);
	}
	inline long long gs(const int ql,const int qr) {
		tmp1=ql,tmp2=qr; return gs(&Root,l,r);
	}
} s(1,1e9);
int n,m,k;
long long ans;
pair<int,pair<int,int> > p[100050];

int main() {
	scanf("%d%d%d",&n,&m,&k);
	for (int i=0; i<k; ++i) scanf("%d%d%d",&p[i].first,
	&p[i].second.first,&p[i].second.second);
	sort(p,p+k);
	for (int i=0; i<k; ++i) {
		long long res=s.gs(1,p[i].second.first)+p[i].second.second;
		s.edi(p[i].second.first,res); ans=max(ans,res);
	}
	cout<<ans;
}

例题:「NOI1998」免费的馅饼

在这里\(x_i=2t_i-s_i\),\(y_i=2t_i+s_i\)(其实除了\(x_i\ge x_j\land y_i\ge y_j\)还有一个约束是\(t_i\ge t_j\),但容易发现只需满足前两个条件,后者也一定满足)

#include <bits/stdc++.h>
using namespace std;
struct segetree {
	int l,r,tmp1,tmp2;
	long long tmp3;
	struct segenode {
		segenode *ls,*rs;
		long long v;
		segenode() {ls=rs=NULL,v=0;}
	} Root;
	void edi(segenode *k,const int l,const int r) {
		if (l==r) return void(k->v=tmp3);
		if (tmp1<=(l+r)/2)
			edi((k->ls?k->ls:(k->ls=new segenode)),l,(l+r)/2);
		else edi((k->rs?k->rs:(k->rs=new segenode)),(l+r)/2+1,r);
		k->v=max((k->ls?k->ls->v:0),(k->rs?k->rs->v:0));
	}
	long long gs(segenode *k,const int l,const int r) {
		if (tmp1>r||tmp2<l) return 0;
		if (tmp1<=l&&r<=tmp2) return k->v;
		return max((k->ls?gs(k->ls,l,(l+r)/2):0),
		(k->rs?gs(k->rs,(l+r)/2+1,r):0));
	}
	segetree(const int l=0,const int r=0):l(l),r(r) {}
	inline void edi(const int p,const long long v) {
		tmp1=p,tmp3=v; edi(&Root,l,r);
	}
	inline long long gs(const int ql,const int qr) {
		tmp1=ql,tmp2=qr; return gs(&Root,l,r);
	}
} s(1,3e8);
pair<int,pair<int,int> > p[100050];
int m,k; long long ans;

int main() {
	scanf("%d%d",&m,&k);
	for (int i=0,ti,pi; i<k; ++i) {
		scanf("%d%d%d",&ti,&pi,&p[i].second.second);
		p[i].first=2*ti-pi;
		p[i].second.first=2*ti+pi;
	}
	sort(p,p+k);
	for (int i=0; i<k; ++i) {
		long long res=s.gs(1,p[i].second.first)+p[i].second.second;
		s.edi(p[i].second.first,res); ans=max(ans,res);
	}
	cout<<ans;
}
posted @ 2021-02-19 11:55  OOmega  阅读(45)  评论(0)    收藏  举报