codeforces C - Perform Easily (尺取法 + 线段树)

题目链接:https://codeforces.com/contest/1435/problem/C

给定 \(n\)\(b_i\),每个 \(b_i\) 可以选择减去\(a_{1,\ldots,6}\)中的一个数字,求新数列中最大值减最小值的最小值

题意很绕,需要仔细理解
将所有的二元组\((b_i-j,i)\),按关键字排好序,双指针扫一遍,当满足位置\(1,\ldots,n\)都出现过以后,更新答案

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 100100;

int n,cnt;
int a[10],b[maxn];

pair<int,int> P[6*maxn];

struct SEG{
	int mi,add;
}t[maxn<<2];

bool cmp(pair<int,int> x,pair<int,int> y){
	if(x.first == y.first){
		return x.second < y.second;
	}else{
		return x.first < y.first;
	}
}

void pushup(int i){ t[i].mi = min(t[i<<1].mi,t[i<<1|1].mi); }

void mdf(int i,int k,int l,int r,int p){
	if(l == r){
		t[i].mi += k;
		return;
	}
	int mid = (l+r)/2;
	if(p<=mid) mdf(i<<1,k,l,mid,p);
	else mdf(i<<1|1,k,mid+1,r,p);
	pushup(i);
}

int qry(int i,int l,int r,int x,int y){
	if(x <= l && r <= y){
		return t[i].mi;
	}
	int mid = (l+r)/2;
	int mi = 1000000007;
	if(x <= mid) mi = min(mi,qry(i<<1,l,mid,x,y));
	if(y > mid) mi = min(mi,qry(i<<1|1,mid+1,r,x,y));
	return mi;
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	for(int i=1;i<=6;++i) a[i] = read();
	n = read(); cnt = 0;
	
	for(int i=1;i<=n;++i){
		b[i] = read();
		for(int j=1;j<=6;++j){
			P[++cnt].first = b[i] - a[j];
			P[cnt].second = i;
		}
	}

	sort(P+1,P+1+cnt,cmp);
	
	int ans = 1000000007;
	for(int l = 0,r = 0; l < cnt; ++l){
		while((qry(1,1,n,1,n) == 0 && r < cnt)){
			++r;
			mdf(1,1,1,n,P[r].second);
		}
		
		if(qry(1,1,n,1,n) != 0) ans = min(ans,P[r].first - P[l+1].first);
		if(l==r){
			++r;
			mdf(1,1,1,n,P[r].second);
		}
		mdf(1,-1,1,n,P[l+1].second);
	}
	
	printf("%d\n",ans);
	
	return 0;
}
posted @ 2020-10-26 01:45  Tartarus_li  阅读(186)  评论(0编辑  收藏  举报