P10281 [USACO24OPEN] Grass Segments G

洛谷

15pts

判断样例即可。

25pts

\(O(n^2)\) 的暴力枚举即可。

55pts

满足条件为 \(\min(r_i,r_j)-\max(l_i,l_j) \ge k_i\) 时,第 \(i\) 个可获得一个品种。

由于被减数取最小值,减数取最大值,那么就必定成立。

  • \(r_i-l_i \ge k_i\)(已知条件)

  • \(r_j-l_j \ge k_i\)

  • \(r_i-l_j \ge k_i\)

  • \(r_j-l_i \ge k_i\)

在所有的 \(k_i\) 均相等时,第二条式子也是必定成立的。

此时这个问题就是一个二维偏序问题了。

那么就可以直接使用树状数组或者归并排序求出,即可解决这一性质的部分。

与前一部分的 \(O(n^2)\) 放在一起即可。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5;
int n,l[N],r[N],k[N],ans[N],tmp[N*2],cnt;
void solve1(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			if(min(r[i],r[j])-max(l[i],l[j])>=k[i])ans[i]++;
		}
	}
}
int lowbit(int x){
	return x&-x;
}
struct BT{
	int c[N];
	void init(){
		memset(c,0,sizeof(c));
	}
	void add(int x,int y){
		for(int i=x;i<=cnt;i+=lowbit(i))c[i]+=y;
	}
	int query(int x){
		int ans=0;
		for(int i=x;i>=1;i-=lowbit(i))ans+=c[i];
		return ans;
	}
}bit;
struct P{
	int l,r,id;
}a[N];
bool cmp(P a,P b){
	if(a.r==b.r)return a.id>b.id;
	return a.r>b.r;
}
void solve2(){
	for(int i=1;i<=n;i++){
		a[++cnt]={r[i]-k[i],l[i]+k[i],i};
		a[++cnt]={l[i],r[i],n+i};
	}
	sort(a+1,a+2*n+1,cmp);
	for(int i=1;i<=2*n;i++)tmp[++cnt]=a[i].l;
	sort(tmp+1,tmp+cnt+1);
	cnt=unique(tmp+1,tmp+cnt+1)-tmp-1;
	for(int i=1;i<=2*n;i++)a[i].l=lower_bound(tmp+1,tmp+cnt+1,a[i].l)-tmp;
	for(int i=1;i<=2*n;i++){
		if(a[i].id>n)bit.add(a[i].l,1);
		else ans[a[i].id]+=bit.query(a[i].l);
	}
	for(int i=1;i<=n;i++)ans[i]--;
}
signed main(){
	cin>>n;
	cnt=0;
	for(int i=1;i<=n;i++){
		cin>>l[i]>>r[i]>>k[i];
	}
	if(n<=5000){
		solve1();
	}
	else {
		solve2();
	}
	for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
	return 0;
}

100pts

根据上一步分析,多出了一个 \(r_j-l_j \ge k_i\),那么就可以直接考虑使用三维偏序。

做三维偏序时,通常使用 CDQ 分治算法。

相较于常规的二维偏序而言,CDQ 分治算法解决三维偏序相当于可以通过树状数组在归并排序中得到每一个点的取值。

我们在存储时建立一组作为被相交形成答案的线段,一组作为查询答案的线段。

在存储结构体时直接将两部分对应的值加入到结构体的对应位置,这样就可以快速地排序处理了。

在清理树状数组时,由于范围较大,直接清空可能会超时,除了使用时间戳优化还可以直接进行逆操作,将之前添加的值删除以此完成清空。

具体细节看又香又短的代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5;
int n,tmp[N],ans[N],cnt;
struct P{
	int l,r,k,id;
}a[N],b[N];
bool cmp(P a,P b){
	if(a.k==b.k)return a.id<b.id;
	return a.k>b.k;
}
int lowbit(int x){
	return x&-x;
}
struct BT{
	int c[N];
	void init(){
		memset(c,0,sizeof(c));
	}
	void add(int x,int y){
		for(int i=x;i<=cnt;i+=lowbit(i))c[i]+=y;
	}
	int query(int x){
		int ans=0;
		for(int i=x;i>=1;i-=lowbit(i))ans+=c[i];
		return ans;
	}
}bit;
void CDQ(int l,int r){
	if(l==r)return ;
	int mid=(l+r)/2;
	CDQ(l,mid);
	CDQ(mid+1,r);
	int L=l,R=mid+1;
	for(int i=l;i<=r;i++){
		if(R>r||L<=mid&&a[L].r>=a[R].r){
			b[i]=a[L];
			if(!a[L].id)bit.add(a[L].l,1);
			L++;
		}
		else {
			b[i]=a[R];
			if(a[R].id)ans[a[R].id]+=bit.query(a[R].l);
			R++;
		}
	}
	for(int i=l;i<=mid;i++)if(!a[i].id)bit.add(a[i].l,-1);
	for(int i=l;i<=r;i++)a[i]=b[i];
}
signed main(){
	cin>>n;
	for(int i=1,l,r,k;i<=n;i++){
		cin>>l>>r>>k;
		a[i]={r-k,l+k,k,i};
		a[n+i]={l,r,r-l,0};
	}
	for(int i=1;i<=2*n;i++)tmp[i]=a[i].l;
	sort(tmp+1,tmp+2*n+1);
	cnt=unique(tmp+1,tmp+2*n+1)-tmp-1;
	for(int i=1;i<=2*n;i++)a[i].l=lower_bound(tmp+1,tmp+cnt+1,a[i].l)-tmp;
	sort(a+1,a+2*n+1,cmp);
	CDQ(1,2*n);
	for(int i=1;i<=n;i++)cout<<ans[i]-1<<endl;
	return 0;
}
posted @ 2025-10-31 09:19  huhangqi  阅读(6)  评论(0)    收藏  举报