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;
}