cf 1208D 树状数组+倍增/线段树

笑着哭i 提交于 2019-11-28 19:19:13

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

此处查找使用倍增的方法。

数组数组+倍增,单次操作O(log n)

树状数组+二分,单次操作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;
}

解法二:线段树

#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;
}

此题与POJ 2182类似。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!