HDU6609 Find the answer 權值線段樹+思維

OJ題號

HDU6609 Find the answer

簡單題意

給 n 個數,前 i−1 個至少要把幾個變成 0 才能使前 i 項的和<= m。

正解思路

思路來自:https://blog.csdn.net/Ratina/article/details/97798320

對於每一個a[i],前綴和sum[i],

  1. 當sum[i]≤m,則ans[i]=0;
  2. 當sum[i]>m[i],我們就要刪除1 ~ i-1的元素(變爲0),爲了刪除的個數最少,很明顯要優先刪除大的元素,但暴力排序肯定不行,這裏就要構建一棵權值線段樹,找到構造成sum-m的最少元素。

對於權值線段樹的建立,我們把a[i]離散化後構建權值線段樹,但裏面存儲的是權值的個數和該權值的總和。

查詢的時候就是查找sum-m最少是多少個權值相加,利用二分的思想在線段樹上查找,大的值優先所以優先查找右子樹。鎖定分界點位置後依然需要用記錄個數的權值線段樹得到ans[i]。

代碼

#include<bits/stdc++.h>
#define LL long long
#define PLL pair<LL,LL>
using namespace std;
const int maxn=2e5+50;
int n,N;
LL m,w[maxn],b[maxn];
LL s[maxn<<2],c[maxn<<2];
void init()
{
    sort(b+1,b+n+1);
    N=unique(b+1,b+n+1)-(b+1);
    for(int i=1; i<=n; i++)
        w[i]=lower_bound(b+1,b+N+1,w[i])-b;
}
void updata(int rt,int l,int r,int p)
{
    if(l==r)
    {
        s[rt]+=b[l];
        c[rt]++;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)
        updata(rt<<1,l,mid,p);
    else
        updata(rt<<1|1,mid+1,r,p);
    s[rt]=s[rt<<1]+s[rt<<1|1];
    c[rt]=c[rt<<1]+c[rt<<1|1];
}
PLL query1(int rt,int l,int r,LL k)
{
    if(l==r)
    {
        if(k%b[l]==0)
            return PLL(l,k/b[l]);
        else
            return PLL(l,k/b[l]+1);
    }
    int mid=(l+r)>>1;
    if(s[rt<<1|1]>=k)
        return query1(rt<<1|1,mid+1,r,k);
    else
        return query1(rt<<1,l,mid,k-s[rt<<1|1]);

}
LL query2(int rt,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
        return c[rt];
    if(r<ql||l>qr)
        return 0;
    int mid=(l+r)>>1;
    return query2(rt<<1,l,mid,ql,qr)+query2(rt<<1|1,mid+1,r,ql,qr);
}
int main()
{
    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%d %lld",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&w[i]);
            b[i]=w[i];
        }
        init();
        memset(s,0,sizeof(s));
        memset(c,0,sizeof(c));
        LL sum=0,ans[maxn];
        for(int i=1; i<=n; i++)
        {
            sum+=b[w[i]];
            if(sum>m)
            {
                PLL temp=query1(1,1,N,sum-m);
                //cout<<temp.first<<" "<<temp.second<<endl;
                ans[i]=temp.second;
                if(temp.first+1<=m)
                    ans[i]+=query2(1,1,N,temp.first+1,m);
            }
            else
                ans[i]=0;
            updata(1,1,N,w[i]);
        }
        for(int i=1; i<=n; i++)
            printf("%lld ",ans[i]);
        printf("\n");
    }
    return 0;
}


結構體

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 2e5+10;
#define lson i<<1
#define rson i<<1|1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define ll long long
#define N 200005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
ll a[N],b[N],b_n,n,m,ans[N];
ll ans_sum,ans_max,ans_min;
//注意一定要找一個臨時變量記錄下ans_***的答案,不然會覆蓋
struct node
{
    int l,r;
    ll sum,num;
} tree[N<<2];
void pushup(int i)
{
    tree[i].sum=tree[lson].sum+tree[rson].sum;
    tree[i].num=tree[lson].num+tree[rson].num;
}
//建立線段樹
void build(int l,int r,int i)
{
    tree[i].l = l;
    tree[i].r = r;
    if(l == r)
    {
        tree[i].sum = 0;
        tree[i].num = 0;
        return;
    }
    int mid = (l+r)>>1;
    build(LS);
    build(RS);
    pushup(i);
}

void add_data(int i,int l,int r,int pos)
{
	
    if(l==r)
    {
        tree[i].sum += b[l];
        tree[i].num++;
        return;
    }

    int mid = (l+r)>>1;
    if(pos<=mid)
        add_data(lson,l,mid,pos);
    else
        add_data(rson,mid+1,r,pos);
    pushup(i);
}

pair<ll,ll> query1(int i,int l,int r,ll val)
{
    //cout<<l<<" "<<r<<" "<<i<<endl;
    if(l == r)
    {
        if(val%b[l]==0)
            return pair<ll,ll>(l,val/b[l]);
        else
            return pair<ll,ll>(l,val/b[l]+1);
    }
    int mid=(l+r)>>1;
    if(tree[i<<1|1].sum>=val)
        return query1(i<<1|1,mid+1,r,val);
    else
        return query1(i<<1,l,mid,val-tree[i<<1|1].sum);

}
LL query2(int i,int l,int r,int ql,int qr)  
{
    if(ql<=l&&r<=qr)
        return tree[i].num;
        
    if(r<ql||l>qr)
        return 0;
        
    int mid=(l+r)>>1;
    
    return query2(i<<1,l,mid,ql,qr)+query2(i<<1|1,mid+1,r,ql,qr);
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            b[i]=a[i];
        }


        sort(b+1,b+n+1);
        b_n=unique(b+1,b+n+1)-(b+1);
        for(int i=1; i<=n; i++)
        {
            a[i]=lower_bound(b+1,b+b_n+1,a[i])-b;
        }
        build(1,b_n,1);

        ll sum=0;
        for(int i=1; i<=n; i++)
        {
            sum+=b[a[i]];
            if(sum<=m)
            {
                ans[i]=0;
            }
            else
            {
                pair<ll,ll> temp=query1(1,1,b_n,sum-m);
                //cout<<temp.first<<" "<<temp.second<<" "<<tree[1].sum<<endl;
                ans[i]=temp.second;
                if(temp.first+1<=m)
                {
                    ans[i]+= query2(1,1,b_n,temp.first+1,m);
                }
	
            }
            add_data(1,1,b_n,a[i]);
        }
        
        for(int i=1;i<n;i++)
		{
			printf("%lld ",ans[i]);
		}
		printf("%lld\n",ans[n]);

    }
    return 0;

}




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章