开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情
分析
这题算一个简单题吧,就是两个板子的结合,我们可以发现,初始化时候所有数都是0,然后每遍历到一个非0的a[i],分两种情况讨论,如果a[i]小于等于i,那么我们就把i-a[i]+1到i放进一个vector,如果a[i]>i,就把1到i放进vector,然后我们进行区间合并,但这里的区间合并和区间合并的板子又不太一样,这里不是要对区间操作,而是要对区间端点操作,所以我们按照左端点排序之后,如果发现后一个左端点大于前一个右端点+1,我们才要把区间分开,否则都可以合并,然后把所有合并之后的区间搞出来之后,我们就可以对这些区间都+1,也就是用一个差分即可,然后这题就愉快地解决了,下面依然看一下化简版的代码,因为原来的代码也是依托答辩。QAQ~!
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
#include <cmath>
#include <unordered_map>
#include <stack>
#include <queue>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
typedef pair<int,int> PII;
typedef pair<string,int> PSI;
typedef stack<int> stk;
int gcd(int x,int y){
return y?gcd(y,x%y):x;
}
ll qmi(ll x,ll y,int mod){
ll res=1;
while(y){
if(y&1) res=res*x%mod;
y>>=1;
x=x*x%mod;
}
return res;
}
const int N=200020;
int a[N],b[N],t,n;
vector<PII> alls,seg;
inline void insert(int l,int r,int c){
b[l]+=c,b[r+1]-=c;
}
inline void solve(){
memset(b,0,sizeof b);
cin>>n;
alls.clear();
seg.clear();
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>=i){
alls.push_back({1,i});
}
if(a[i]<i && a[i]!=0){
alls.push_back({i-a[i]+1,i});
}
}
if(alls.size()==0){
for(int i=1;i<=n;i++) cout<<b[i]<<" ";
cout<<endl;
return;
}
sort(alls.begin(),alls.end());
int rr=alls[0].second,lll=alls[0].first;
for(auto &[l,r]:alls){
if(l<=rr+1) rr=max(rr,r);
else{
seg.push_back({lll,rr});
lll=l;
rr=max(rr,r);
}
}
seg.push_back({lll,rr});
for(auto &[l,r]:seg) insert(l,r,1);
for(int i=1;i<=n;i++){
b[i]+=b[i-1];
cout<<b[i]<<" ";
}
cout<<"\n";
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}