P2468 [SDOI2010]粟粟的书架(主席树)

题目链接

题面:
在这里插入图片描述

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define ll long long
#define llu unsigned ll
#define pr make_pair
#define pb push_back
#define y1 yy
using namespace std;
const int maxn=500100;
const int maxk=1005;
int sum[210][210][1010],num[210][210][1010];
int a[210][210];
int root[maxn];
struct node
{
    int lc,rc;
    int sum,si;
}t[maxn*22];

int r,c,m,cnt=0;
int x1,y1,x2,y2,h;

void pushup(int p)
{
    t[p].si=t[t[p].lc].si+t[t[p].rc].si;
    t[p].sum=t[t[p].lc].sum+t[t[p].rc].sum;
}

int _insert(int now,int l,int r,int pos)
{
    int p=++cnt;
    t[p]=t[now];
    if(l==r)
    {
        t[p].si++;
        t[p].sum+=pos;
        return p;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) t[p].lc=_insert(t[now].lc,l,mid,pos);
    else t[p].rc=_insert(t[now].rc,mid+1,r,pos);
    pushup(p);
    return p;
}

int ask(int pl,int pr,int l,int r,int k)
{
    if(l==r)
    {
        //需要多少本书
        if(t[pr].sum-t[pl].sum>=k)
            return k/l+(k%l!=0);
    }
    int mid=(l+r)>>1;
    int ans=t[t[pr].rc].sum-t[t[pl].rc].sum;
    if(ans<k) return t[t[pr].rc].si-t[t[pl].rc].si+ask(t[pl].lc,t[pr].lc,l,mid,k-ans);
    else return ask(t[pl].rc,t[pr].rc,mid+1,r,k);
}

//r==1时是一条链,转化为贪心取厚的书。
void do_it1(void)
{
    int x;
    for(int i=1;i<=c;i++)
        scanf("%d",&x),root[i]=_insert(root[i-1],1,maxk,x);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);
        if(t[root[y2]].sum-t[root[y1-1]].sum<h)
            printf("Poor QLW\n");
        else
            printf("%d\n",ask(root[y1-1],root[y2],1,maxk,h));

    }
}



int get_sum(int x1,int y1,int x2,int y2,int k)
{
    return sum[x2][y2][k]-sum[x2][y1-1][k]-sum[x1-1][y2][k]+sum[x1-1][y1-1][k];
}
int get_num(int x1,int y1,int x2,int y2,int k)
{
    return num[x2][y2][k]-num[x2][y1-1][k]-num[x1-1][y2][k]+num[x1-1][y1-1][k];
}

void do_it2(void)
{
    for(int i=1;i<=r;i++)
    {
        for(int j=1;j<=c;j++)
        {
            scanf("%d",&a[i][j]);
            for(int k=0;k<=maxk;k++)
            {
                sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(a[i][j]>=k?a[i][j]:0);
                num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(a[i][j]>=k);
            }
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);
        int l=0,r=maxk;
        int mid,ans=-1;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(get_sum(x1,y1,x2,y2,mid)>=h) ans=mid,l=mid+1;
            else r=mid-1;
        }
        //某一高度(ans)的书本可能不需要全用
        if(ans==-1) printf("Poor QLW\n");
        else printf("%d\n",get_num(x1,y1,x2,y2,ans)-(get_sum(x1,y1,x2,y2,ans)-h)/ans);
    }
}

int main(void)
{
    scanf("%d%d%d",&r,&c,&m);
    if(r==1) do_it1();
    else do_it2();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值