CF1710B&如何理解一阶/二阶差分后最值取点数量只有 O(n)

如何理解一阶/二阶差分后最值取点数量只有 \(O(n)\)

一阶的显然。

考虑一系列操作都可以化成 \(O(n)\) 个单点二阶差分加。

考虑对于 2 个不为 0 的二阶差分,\(i,j\),那么 \((i,j)\) 这个区间是不是一阶差分都一样,那么最后的前缀和是不是 \(i+1\) 叠的值最少,\(j-1\) 叠的最多,所以最值一定在 \(i,i+1,j-1,j\) 四个位置出现。然后加可能负数,所以对于每个二阶差分单点加的点只要顺带记录它 \(+-1\) 即可。

https://codeforces.com/contest/1710/problem/B

例题捏!

考虑转化为 2 个等差数列,那么显然二阶差分。至于怎么加这个就需要现场手推了。然后就记录下 \(+-1\),最后判断下就好了。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
int rd() {
	int sum=0,f=1; char ch=getchar();
	while(ch>'9'||ch<'0') {
		if(ch=='-') f=-1;
		ch=getchar(); 
	}
	while(ch<='9'&&ch>='0') {
		sum=sum*10+ch-'0'; ch=getchar();
	}
	return sum*f;
}
const int N=(int)(2e6+5),inf=(int)(2e18);
struct ques {
	int x,p;
}a[N];
pair<int,int>d[N],A[N];
int n,m,mx1[N],mx2[N];
map<int,int>mp,mp2;

void solve() {
	n=rd(); m=rd(); mp.clear(); mp2.clear();
//	add2(1,5,0);
	for(int i=1;i<=n;i++) {
		int x=rd(),p=rd(); a[i].x=x; a[i].p=p;
		mp[x]+=0; mp[x-1]+=0; mp[x+p-1]+=0; mp[x+p]+=0;
		mp[x-p+1]++; mp[x+1]+=-1-p; mp[x+2]+=p;
		--p;
		if(p>=0) {
			mp[x+1]+=p; mp[x+2]+=-1-p; mp[x+p+2]+=1;
		} 
	}
	int tot=0;
	for(auto it=mp.begin();it!=mp.end();++it) {
//		cout<<(*it).first<<" "<<(*it).second<<'\n';
		++tot; mp2[(*it).first]=tot; d[tot]=make_pair((*it).first,(*it).second);
	}
	sort(d+1,d+1+tot);
//	cout<<'\n';
//	d[0]=make_pair(0,0);
	for(int i=2;i<=tot;i++) d[i].second+=d[i-1].second;
//	for(int i=1;i<=tot;i++) {
////		d[i].second+=d[i-1].second*(d[i].first-d[i-1].first);
//		cout<<d[i].first<<" "<<d[i].second<<'\n'; 
//	}
//	cout<<'\n';
	A[1]=d[1];
	for(int i=2;i<=tot;i++) {
		A[i].first=d[i].first;
		if(d[i].first==d[i-1].first+1) A[i].second=d[i].second+A[i-1].second;
		else A[i].second=d[i].second+A[i-1].second+d[i-1].second*(d[i].first-d[i-1].first-1);
//		cout<<d[i].first<<" "<<A[i].second<<'\n'; 
	}
//	cout<<'\n';
//	for(int i=1;i<=tot;i++) cout<<A[i].first<<" "<<A[i].second<<'\n';
	mx1[0]=mx2[tot+1]=-inf;
	for(int i=1;i<=tot;i++) {
		if(A[i].second>m) mx1[i]=max(mx1[i-1],A[i].second-A[i].first);
		else mx1[i]=mx1[i-1];
	}
	for(int i=tot;i>=1;i--) {
		if(A[i].second>m) mx2[i]=max(mx2[i+1],A[i].first+A[i].second);
		else mx2[i]=mx2[i+1];
	}
//	for(int i=1;i<=n;i++) {
//		bool fl=1;
//		for(int j=1;j<=tot;j++) {
//			int qwq=max(0ll,a[i].p-abs(a[i].x-A[j].first));
//			if(A[j].second-qwq>m) {
//				fl=0; break ;
//			}
//		}
//		if(fl) printf("1");
//		else printf("0");
//	}
//	int res=0;
	for(int i=1;i<=n;i++) {
		int id=mp2[a[i].x];
//		cout<<id<<" "<<mx1[id]<<" "<<mx2[id]<<'\n';
		if(mx1[id]<=m+a[i].p-a[i].x&&mx2[id]<=m+a[i].p+a[i].x) {
			printf("1");
		} else printf("0");
	}
	printf("\n");
	for(int i=0;i<=tot;i++) {
		mx1[i]=mx2[i]=-inf; A[i]=d[i]=make_pair(0,0);
	}
}

signed main() {
	int T=rd(); while(T--) solve();
	return 0;
}
posted @ 2022-07-30 00:52  FxorG  阅读(74)  评论(0编辑  收藏  举报