题解 数对

传送门

我一定是傻了一直觉得这题是spfa求最长路
然后等我写完发现过不了样例,手模发现有后效性的时候整个人傻了

  • 给一堆二元组,要什么 \(i<j\)\(a_i \leqslant b_j\) 之类的题切入点基本都是「×××一定更优」

但我一开始没找到这样的性质
其实也很简单,若 \(a_i<a_j\)\(b_i<b_j\)\(i\) 一定放在 \(j\) 前面
其它没有这个性质的顺序可以随意,不会证
那按 \(a+b\) 排个序就可以满足这个性质了
然后DP和队长快跑类似,区间取max可以转化为单点

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define fir first
#define sec second
#define make make_pair
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int uni[N<<1], usize;
struct couple{int a, b; ll w;}p[N];
inline bool operator < (couple a, couple b) {return a.a+a.b<b.a+b.b;}
inline bool operator < (pair<ll, int> a, pair<ll, int> b) {return a.fir==b.fir?a.sec>b.sec:a.fir<b.fir;}
int tl[N<<3], tr[N<<3]; ll tag[N<<3]; pair<ll, int> maxn[N<<3];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define maxn(p) maxn[p]
#define tag(p) tag[p]
#define pushup(p) maxn(p)=max(maxn(p<<1), maxn(p<<1|1))
void spread(int p) {
	if (!tag(p)) return ;
	maxn(p<<1).fir+=tag(p); tag(p<<1)+=tag(p);
	maxn(p<<1|1).fir+=tag(p); tag(p<<1|1)+=tag(p);
	tag(p)=0;
}
void build(int p, int l, int r) {
	tl(p)=l; tr(p)=r;
	if (l==r) return ;
	int mid=(l+r)>>1;
	build(p<<1, l, mid);
	build(p<<1|1, mid+1, r);
}
void upd(int p, int pos, pair<ll, int> dat) {
	if (tl(p)==tr(p)) {maxn(p)=max(maxn(p), dat); return ;}
	spread(p);
	int mid=(tl(p)+tr(p))>>1;
	if (pos<=mid) upd(p<<1, pos, dat);
	else upd(p<<1|1, pos, dat);
	pushup(p);
}
void upd(int p, int l, int r, ll dat) {
	if (l<=tl(p) && r>=tr(p)) {maxn(p).fir+=dat; tag(p)+=dat; return ;}
	spread(p);
	int mid=(tl(p)+tr(p))>>1;
	if (l<=mid) upd(p<<1, l, r, dat);
	if (r>mid) upd(p<<1|1, l, r, dat);
	pushup(p);
}
pair<ll, int> query(int p, int l, int r) {
	if (l<=tl(p) && r>=tr(p)) return maxn(p);
	spread(p);
	int mid=(tl(p)+tr(p))>>1; pair<ll, int> ans=make(0, 0);
	if (l<=mid) ans=max(ans, query(p<<1, l, r));
	if (r>mid) ans=max(ans, query(p<<1|1, l, r));
	return ans;
}

signed main()
{
	n=read();
	for (int i=1; i<=n; ++i) {
		p[i].a=read(); p[i].b=read(); p[i].w=read();
		uni[++usize]=p[i].a; uni[++usize]=p[i].b;
	}
	sort(uni+1, uni+usize+1);
	usize=unique(uni+1, uni+usize+1)-uni-1;
	for (int i=1; i<=n; ++i) {
		p[i].a=lower_bound(uni+1, uni+usize+1, p[i].a)-uni;
		p[i].b=lower_bound(uni+1, uni+usize+1, p[i].b)-uni;
	}
	sort(p+1, p+n+1);
	//for (int i=1; i<=n; ++i) cout<<p[i].a<<' '<<p[i].b<<endl;
	build(1, 1, usize);
	pair<ll, int> tem;
	for (int i=1; i<=n; ++i) {
		//cout<<"i: "<<i<<endl;
		if (p[i].a<p[i].b) upd(1, p[i].a+1, p[i].b, p[i].w);
		tem=query(1, 1, min(p[i].a, p[i].b));
		//cout<<i<<": "<<tem.fir<<' '<<tem.sec<<' '<<tem.fir+p[i].w<<endl;
		upd(1, p[i].a, make(tem.fir+p[i].w, p[i].a));
		//cout<<endl;
	}
	printf("%lld\n", query(1, 1, usize).fir);
	
	return 0;
}
posted @ 2021-08-12 20:11  Administrator-09  阅读(12)  评论(0编辑  收藏  举报