CF526F Pudding Monsters 题解
CF526F Pudding Monsters 题解
知识点
分治。
分析
输入的点是 \((x_i,y_i)\),我们把它记为 \(a_{x_i} \gets y_i\),以此转换到序列上。
我们发现,一段区间 \([l,r]\) 最多只有一种合法情况,且需满足 \(\max_{i=l}^{r}a_i - \min_{i=l}^{r}a_i + 1 = r-l+1\),这条式子也可以解释为:区间 \([l,r]\) 上的数值按顺序排放后恰好是连续的。
那么我们就可以分治了。
假设我们此时所在区间为 \([l,r]\),中点即为 \(mid\),那么左端点位于 \([l,mid]\),右端点位于 \((mid,r]\)。
枚举左端点 \(i\),对于区间 \(\max,\min\),有三种情况:
- 右端点 \(j\) 在 \((mid,it_0]\),区间 \(\max,\min\) 都在 \([i,mid]\) 中;
- 右端点 \(j\) 在 \((it_0,it_1]\),区间 \(\max,\min\) 其中之一在 \([i,mid]\) 中;
- 右端点 \(j\) 在 \((it_1,r]\),区间 \(\max,\min\) 都不在 \([i,mid]\) 中;
那么就非常简单,对于 1,直接分支判断,对于 2、3,将 \(\max_{i=l}^{r}a_i - \min_{i=l}^{r}a_i + 1 = r-l+1\) 这条式子移项转换一下,将定项与不定项分开,再都开个桶数组即可。
CODE
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define max(a,b) ((a)<(b)?(b):(a))
#define min(a,b) ((a)>(b)?(b):(a))
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define DOR(i,a,b) for(register int i=(a);i>=(b);--i)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
const int N=3e5+10,B=N-10;
int n;
ll ans;
int it[2],a[N],cnt[N<<1][3],mi[N],mx[N];
#define mid (l+r>>1)
void Separation(int l,int r){
if(l==r)return ++ans,void();
Separation(l,mid),Separation(mid+1,r);
mi[mid]=mx[mid]=a[mid],mi[mid+1]=mx[mid+1]=a[mid+1],it[0]=it[1]=mid;
FOR(i,mid+2,r)mx[i]=max(mx[i-1],a[i]),mi[i]=min(mi[i-1],a[i]);
DOR(i,mid-1,l)mx[i]=max(mx[i+1],a[i]),mi[i]=min(mi[i+1],a[i]);
FOR(i,mid+1,r)if(l<=i-mx[i]+mi[i]&&i-mx[i]+mi[i]<=mid)++cnt[i-mx[i]+mi[i]][0];
DOR(i,mid,l){
while(it[1]<r&&(mi[i]<=mi[it[1]+1]||mx[i]>=mx[it[1]+1])){
++it[1],++cnt[it[1]+mi[it[1]]][1],++cnt[B+it[1]-mx[it[1]]][2];
if(l<=it[1]-mx[it[1]]+mi[it[1]]&&it[1]-mx[it[1]]+mi[it[1]]<=mid)
--cnt[it[1]-mx[it[1]]+mi[it[1]]][0];
}
while(it[0]<r&&(mi[i]<=mi[it[0]+1]&&mx[i]>=mx[it[0]+1]))
++it[0],--cnt[it[0]+mi[it[0]]][1],--cnt[B+it[0]-mx[it[0]]][2];
ans+=(mid<i+mx[i]-mi[i]&&i+mx[i]-mi[i]<=it[0])+cnt[i][0];
ans+=(mx[i]>mx[it[1]]?cnt[i+mx[i]][1]:cnt[B+i-mi[i]][2]);
}
FOR(i,mid+1,r)if(l<=i-mx[i]+mi[i]&&i-mx[i]+mi[i]<=mid)cnt[i-mx[i]+mi[i]][0]=0;
FOR(i,mid+1,r)cnt[i+mi[i]][1]=0,cnt[B+i-mx[i]][2]=0;
}
#undef mid
signed main(){
cin>>n;
FOR(i,1,n){
int x,y;
cin>>x>>y,a[x]=y;
}
Separation(1,n);
cout<<ans<<endl;
return 0;
}
反思
来久违的写个反思吧。
首先,考场上我想到了 B 题与 E 题的做法,但是 B 题在犹豫之后,多想了一些条件,导致我直接跳过了它,而 E 题则是条件想得过于多了,导致打了好久,最后也没打出来。
C、D 题直接被我舍弃了,在 A 题上花的时间也略多。
提示
这题也可以用线段树做。

浙公网安备 33010602011771号