https://codingcompetitions.withgoogle.com/kickstart/round/0000000000050edd/00000000001a274e
题目大意:
t
t
t组数据,每组给一个数组
a
a
a,对于每个
i
i
i,输出最大的
a
n
s
i
ans_i
ansi,使得
a
[
1
…
…
i
]
a[1……i]
a[1……i]中至少有
a
n
s
i
ans_i
ansi个数
>
=
a
n
s
i
>=ans_i
>=ansi。
思路:考虑用 c n t [ i ] cnt[i] cnt[i]记录 > = i >=i >=i的元素个数,那么对于 a i a_i ai,显然要令 c n t [ 1 … … a i ] cnt[1……a_i] cnt[1……ai]都加 1 1 1,我们设第 i − 1 i-1 i−1次的答案为 a n s i − 1 ans_{i-1} ansi−1,在完成上述加法操作之后,我们设 a n s i = a n s i − 1 ans_i=ans_{i-1} ansi=ansi−1,只要满足 c n t [ a n s i ] > = a n s i cnt[ans_i]>=ans_i cnt[ansi]>=ansi,就可以自增 a n s i ans_i ansi。区间加法、单点求值,线段树可解。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct Tree
{
int l,r,v,lazy;
}tree[maxn<<2];
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
tree[i].lazy=tree[i].v=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
inline void down(int i)
{
tree[i<<1].v+=tree[i].lazy;
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1|1].v+=tree[i].lazy;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i].lazy=0;
}
void update(int i,int l,int r)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].lazy+=1;
tree[i].v+=1;
return ;
}
if(tree[i].lazy)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
update(i<<1,l,r);
else if(l>mid)
update(i<<1|1,l,r);
else
update(i<<1,l,mid),update(i<<1|1,mid+1,r);
}
int get(int i,int pos)
{
if(tree[i].l==tree[i].r)
return tree[i].v;
if(tree[i].lazy)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(pos<=mid)
return get(i<<1,pos);
else
return get(i<<1|1,pos);
}
int main()
{
int t,times=0;
scanf("%d",&t);
while(t--)
{
memset(tree,0,sizeof(tree));
printf("Case #%d:",++times);
int ans=1,MAX=1e5,v,n;
build(1,1,MAX);
scanf("%d",&n);
while(n--)
{
scanf("%d",&v);
update(1,1,v);
while(get(1,ans)>=ans)
++ans;
printf(" %d",--ans);
}
printf("\n");
}
return 0;
}