cf 1208D + tree multiplier array / segment tree

给定一个长度为n的s序列,s_{i}表示前i-1个数中有比i小的数的总和,输出原序列p(1-n每个数出现一次)

Solution to a tree array:

倒序,对于每个s_{i},找出从1-n中的未被利用且和为s_{i}的前缀和,则p_{i}为这些数中最大的数+1,每次找都后需要及时删去

Here for multiplication method.

Arrays Arrays + multiplier, a single operation O (log n)

+ Binary tree arrays, a single operation O (log n * log n)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll s[200050], c[200050];
ll p[25];
int n, t, h[200050];
void add(int x, int t)
{
    while (x <= n)
    {
        c[x] -= t;
        x += x&-x;
    }
}
int main()
{
    p[0] = 1;
    for (int i = 1; i<22; i++)p[i] = p[i - 1] << 1;
    scanf("%d",&n);
    t = log(n) / log(2);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld",&s[i]);
        c[i] += i;
        if (i + (i&-i) <= n)c[i + (i&-i)] += c[i];
    }
    //  for(int i=1;i<=n;i++)
    //     cout<<c[i]<<" ";
    //   cout<<endl;
    for (int i = n; i; i--)
    {
        int ans = 0; ll sum = 0;
        for (int j = t; j >= 0; j--) {    
            if (ans + p[j] <= n && sum + c[ans + p[j]] <= s[i] ) {
                sum += c[ans + p[j]];
                ans += p[j];
            }
        }
        h[i] = ans+1;
        add(ans+1, ans+1);
    }
    for (int i = 1; i <= n; i++) printf("%d ", h[i]);
    puts("");
    return 0;
}

Solution two: segment tree

#include<bits/stdc++.h>
#pragma GCC optimize(3)
#define max(a,b) a>b?a:b
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll tr[N<<2];
ll s[N];
int pos[N];
void build(int l,int r,int p){
    if(l==r){
        tr[p]=l;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    tr[p]=tr[p<<1]+tr[p<<1|1];
}
int query(int l,int r,int p,ll val){
    if(l==r){
        tr[p]=0;
        return l;
    }
    int mid=(l+r)>>1;
    int ans=0;
    if(tr[p<<1]>val){
        ans=query(l,mid,p<<1,val);
        tr[p]-=ans;
    }
    else{
        ans=query(mid+1,r,p<<1|1,val-tr[p<<1]);
        tr[p]-=ans;
    }
    return ans;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%I64d",&s[i]);
    build(1,n,1);
    for(int i=n;i>=1;i--){
        pos[i]=query(1,n,1,s[i]);
    }
    for(int i=1;i<=n;i++) printf("%d%c",pos[i]," \n"[i==n]);
    return 0;
}

This problem is similar to POJ 2182.

Guess you like

Origin www.cnblogs.com/nuchenghao/p/11422058.html