考点: 线段树
题意:有一个长的为 n n n ,由 0 0 0 和 1 1 1 组成的数组,定义一个函数 f ( k , A ) f(k,A) f(k,A) ,它返回另一个数组 B B B ,即对 A A A 的前 k k k 个元素按非递减的顺序排序的结果。例如, f ( 4 , [ 0 , 1 , 1 , 0 , 1 , 0 ] ) = [ 0 , 0 , 1 , 1 , 1 , 0 ] f(4,[0,1,1,0,1,0]) = [0,0,1,1,1,0] f(4,[0,1,1,0,1,0])=[0,0,1,1,1,0] 。注意,前 4 4 4 个元素被排序。现考虑由 f ( 1 , A ) , f ( 2 , A ) , ⋅ ⋅ ⋅ , f ( n , A ) f(1,A),f(2,A),···,f(n,A) f(1,A),f(2,A),⋅⋅⋅,f(n,A) 生成数组 B 1 , B 2 , ⋅ ⋅ ⋅ , B n B_1,B_2,···,B_n B1,B2,⋅⋅⋅,Bn 。 C C C 是通过取 B 1 , B 2 , ⋅ ⋅ ⋅ , B n B_1,B_2,···,B_n B1,B2,⋅⋅⋅,Bn 的元素之和得到的数组。
例如,让 A = [ 0 , 1 , 0 , 1 ] A = [0,1,0,1] A=[0,1,0,1] ,则有 B 1 = [ 0 , 1 , 0 , 1 ] , B 2 = [ 0 , 1 , 0 , 1 ] , B 3 = [ 0 , 0 , 1 , 1 ] , B 4 = [ 0 , 0 , 1 , 1 ] B_1 = [0,1,0,1],B_2 = [0,1,0,1],B_3 = [0,0,1,1],B_4 = [0,0,1,1] B1=[0,1,0,1],B2=[0,1,0,1],B3=[0,0,1,1],B4=[0,0,1,1] ,得到的 C = B 1 + B 2 + B 3 + B 4 = [ 0 , 2 , 2 , 4 ] C = B_1 + B_2 + B_3 + B_4 = [0,2,2,4] C=B1+B2+B3+B4=[0,2,2,4] 。
现在得到数组 C C C ,需要按照上述的方法确定数组 A A A 。
思路:
- 利用公式 k = ∑ 1 n C i n k = \frac{\sum_{1}^{n}{C_i}}{n} k=n∑1nCi 可以求出数组 A A A 中有都少个 1 1 1 ,利用最后一行的有序性,最后 k k k 个值一定为 1 1 1 。
- B 1 B_1 B1 只有第 1 1 1 个有序, B 2 B_2 B2 只有前 2 2 2 个有序, B 3 B_3 B3 只有前 3 3 3 个有序,依此类推, B n − 1 B_{n-1} Bn−1 只有前 n − 1 n-1 n−1 个有序。当确定的第 n n n 行的第 n n n 个值时,用 C n − k n n − 1 \frac{C_n - k_n}{n-1} n−1Cn−kn 便是 A n A_n An 的值。
- 在求 A n − 1 A_{n-1} An−1 的时间需要先将 C k , . . . , n − 1 C_{k,...,n} - 1 Ck,...,n−1 ,再用公式 k = ∑ 1 n − 1 C i n − 1 k = \frac{\sum_{1}^{n-1}{C_i}}{n-1} k=n−1∑1n−1Ci ,接下来的思路与第二点相同。
需要注意的是,本题的数据会爆 i n t int int ,所以需要用 l o n g l o n g long\text{ }long long long
#include<stdio.h>
typedef long long ll;
const int N = 2e5 + 10;
ll a[N],c[N];
struct node{
int l,r;
ll b,x;
}tr[4 * N];
void up(int p) {
if(tr[p].x == 0) return ;
tr[p * 2].b += tr[p].x * (tr[p * 2].r - tr[p * 2].l + 1);
tr[p * 2 + 1].b += tr[p].x * (tr[p * 2 + 1].r - tr[p * 2 + 1].l + 1);
tr[p * 2].x += tr[p].x;
tr[p * 2 + 1].x += tr[p].x;
tr[p].x = 0;
}
void build(int p,int l,int r) {
tr[p].l = l;tr[p].r = r;tr[p].x = 0;tr[p].b = 0;
if(l == r) {
scanf("%lld",&tr[p].b);
return ;
}
int mid = (l + r) >> 1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tr[p].b = tr[p*2].b + tr[p*2+1].b;
}
void modify(int p,int l,int r,int x) {
if(l <= tr[p].l && r >= tr[p].r) {
tr[p].b += x * (tr[p].r - tr[p].l + 1);
tr[p].x += x;
return ;
}
up(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(mid >= l) modify(p*2,l,r,x);
if(mid < r) modify(p*2+1,l,r,x);
tr[p].b = tr[p*2].b + tr[p*2+1].b;
}
ll query(int p,int l,int r) {
if(tr[p].l >= l && r >= tr[p].r) return tr[p].b;
up(p);
int mid = (tr[p].l + tr[p].r) >> 1;
ll k = 0;
if(mid >= l) k += query(p*2,l,r);
if(mid < r) k += query(p*2+1,l,r);
return k;
}
ll ask(int p,int k) {
if(tr[p].l == tr[p].r) return tr[p].b;
up(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(mid >= k) return ask(p*2,k);
else return ask(p*2+1,k);
}
int main(){
int t;
scanf("%d",&t);
while(t --) {
int n;
scanf("%d",&n);
build(1,1,n);
for(int i=n;i>=1;i--) {
ll L = query(1,1,i) / i;
if(i == 1) {
a[i] = L;
break;
}
if(L > 0) modify(1,i-L+1,i,-1);
ll b = ask(1,i);
a[i] = b / (i - 1);
}
for(int i=1;i<=n;i++) printf("%lld ",a[i]);
printf("\n");
}
}