CF1270H Number of Components 题解
这个题目一眼不是很好维护,首先我们想到可以分块离线下来,每\(B\)个一块,提前跑完除了关键点位(也就是这\(B\)次询问的点位)以外的答案,然后容易发现这会形成一片二元点对\((x_i,y_i)\),容易发现\(x_i > x_{i-1} , y_i < y_{i-1}\),这\(B\)个点每一个对应一段上面的区间,一个点对应的按照题目要求的二元点对一定是连续的区间,二分求一个区间覆盖范围即可,复杂度\(O(n \sqrt {n \log2 n} )\)。(已经可以通过了,但会有点卡常,至少没有之前写的Ynoi的卡常就是了。)
再进行一个简单的处理,每处理一块询问我们用桶代替二分,记\(v\)为值域范围,复杂度为$v \frac{q}{B} + qB \(。\)B$取值\(1000\),复杂度比上面小一个$ \frac{1}{3} $,但还是\(10^9\)级别。
不知各位有没有发现什么端倪,我们漏掉了一些很重要的性质。
注意到我们在处理观察出一个中间的点对应的是一段连续的区间,我们考虑从最后一个个往前加点,就会发现每一个联通块对应原数组上一个连续的区间。
那么答案就相当于让我们求$\sum_{i=1}^{i \le n} [ [\min_{j=1}^{j \le i} a_j] > [\max_{ j = i+1 }^{j \le n} a_j] ] $。
我们以前半部分最小的值作为分界线,大于它的记作\(1\),小于它的记作\(0\),那么容易发现答案点列一定是\(11111……1111100000……0000\),(为了方便,我们记\(a_0=1e6+10,a_{n+1}=0\),统计的时候注意一下就可以了)。
我们注意到一个序列最少有一个\(1\)和\(0\)相邻,我们要求的是\(1\)与\(0\)仅相邻一次的个数,统计最小次数即可。
最后还要保证你的这个数在\(a_1~a_n\)中出现过,原因显然。
代码:
#include <bits/stdc++.h>
#define lid (id<<1)
#define rid (id<<1|1)
#define mid ((l+r)/2)
using namespace std;
const int maxn=5e5+10;
int n,Q,a[maxn],jie=1e6,x,y;
struct edge{
int lazy;
int mn;
int sz;
}tree[maxn<<3];
void push_down(int id){
if(tree[id].lazy){
tree[lid].lazy+=tree[id].lazy;
tree[rid].lazy+=tree[id].lazy;
tree[lid].mn+=tree[id].lazy;
tree[rid].mn+=tree[id].lazy;
tree[id].lazy=0;
}
return;
}
void push_up(int id){
tree[id].mn=min(tree[lid].mn,tree[rid].mn);
tree[id].sz=0;
if(tree[id].mn==tree[lid].mn){
tree[id].sz+=tree[lid].sz;
}
if(tree[id].mn==tree[rid].mn){
tree[id].sz+=tree[rid].sz;
}
return;
}
void add(int id,int l,int r,int q,int w,int qw){
if(q<=l&&r<=w){
tree[id].lazy+=qw;
tree[id].mn+=qw;
return;
}
push_down(id);
if(q<=mid){
add(lid,l,mid,q,w,qw);
}
if(w>mid){
add(rid,mid+1,r,q,w,qw);
}
push_up(id);
return;
}
void add(int id,int l,int r,int q,int w){
if(l==r){
tree[id].sz=w;
return;
}
push_down(id);
if(q<=mid){
add(lid,l,mid,q,w);
}
else{
add(rid,mid+1,r,q,w);
}
push_up(id);
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>Q;
a[0]=jie+1;
a[n+1]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
add(1,1,jie+1,a[i],1);
}
for(int i=0;i<=n;i++){
add(1,1,jie+1,min(a[i],a[i+1])+1,max(a[i],a[i+1]),1);
}
while(Q--){
cin>>x>>y;
add(1,1,jie+1,min(a[x-1],a[x])+1,max(a[x-1],a[x]),-1);
add(1,1,jie+1,min(a[x],a[x+1])+1,max(a[x],a[x+1]),-1);
add(1,1,jie+1,a[x],0);
a[x]=y;
add(1,1,jie+1,min(a[x-1],a[x])+1,max(a[x-1],a[x]),1);
add(1,1,jie+1,min(a[x],a[x+1])+1,max(a[x],a[x+1]),1);
add(1,1,jie+1,a[x],1);
cout<<tree[1].sz<<'\n';
}
return 0;
}
浙公网安备 33010602011771号