BZOJ 1926 粟粟的书架(线段树+treap)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1926

题意:

思路:(1)对于R、C<=200的,用f[i][j][k]表示到达(i,j)数字k出现的次数。对于询问暴力统计即可;

(2)对于R=1的,用线段树套个treap,二分查询。






struct node
{
    int val,size,pri,L,R,cnt,sum;
};
  
  
node a[N*27];
int e;


int newNode(int val)
{
    int x=++e;;
    a[x].val=val;
    a[x].sum=val;
    a[x].size=1;
    a[x].cnt=1;
    a[x].L=a[x].R=0;
    a[x].pri=rand();
    return x;
}
 
void pushUp(int x)
{
    if(x==0) return;
    a[x].size=a[x].cnt+a[a[x].L].size+a[a[x].R].size;
    a[x].sum=a[x].cnt*a[x].val+a[a[x].L].sum+a[a[x].R].sum;
}
 
void rotL(int &x)
{
    int y=a[x].R;
    a[x].R=a[y].L;
    a[y].L=x;
      
    pushUp(x);
    pushUp(y);
    x=y;
}
  
void rotR(int &x)
{
    int y=a[x].L;
    a[x].L=a[y].R;
    a[y].R=x;
      
    pushUp(x);
    pushUp(y);
    x=y;
}
  
void insert(int &k,int val)
{
    if(k==0) k=newNode(val);
    else if(val<a[k].val) 
    {
        insert(a[k].L,val);
        if(a[a[k].L].pri>a[k].pri) rotR(k);
    }
    else if(val>a[k].val)
    {
        insert(a[k].R,val);
        if(a[a[k].R].pri>a[k].pri) rotL(k);
    }
    else a[k].cnt++;
    pushUp(k);
}
   
int d[N],sum[N];
  
pair<int,int> getCnt(int t,int x)
{
    if(t==0) return MP(0,0);
    int cnt,sum;
    if(a[t].val==x) 
    {
        cnt=a[a[t].R].size+a[t].cnt;
        sum=a[a[t].R].sum+a[t].cnt*a[t].val;
        return MP(cnt,sum);
    }
    if(a[t].val<x) return getCnt(a[t].R,x);
    pair<int,int> p=getCnt(a[t].L,x);
    p.first+=a[t].cnt+a[a[t].R].size;
    p.second+=a[t].cnt*a[t].val+a[a[t].R].sum;
    return p;
}


struct Node
{
    int L,R,root;
};


Node A[N<<2];


void build(int t,int L,int R)
{
    A[t].L=L;
    A[t].R=R;
    A[t].root=newNode(d[L]);
    int i;
    for(i=L+1;i<=R;i++) insert(A[t].root,d[i]);
    if(L==R) return;
    int M=(L+R)>>1;
    build(t*2,L,M);
    build(t*2+1,M+1,R);
}


pair<int,int> search(int t,int L,int R,int x)
{
    if(A[t].L==L&&A[t].R==R) return getCnt(A[t].root,x);
    int M=(A[t].L+A[t].R)>>1;
    if(R<=M) return search(t*2,L,R,x);
    if(L>M) return search(t*2+1,L,R,x);
    pair<int,int> p,q;
    p=search(t*2,L,M,x);
    q=search(t*2+1,M+1,R,x);
    p.first+=q.first;
    p.second+=q.second;
    return p;
}


void cal(int L,int R,int x)
{
    if(sum[R]-sum[L-1]<x) 
    {
        puts("Poor QLW");
        return;
    }
    pair<int,int> p;
    int low=0,high=1001,mid,t;
    while(low<=high)
    {
        mid=(low+high)>>1;
        p=search(1,L,R,mid);
        if(p.second<x) high=mid-1;
        else low=mid+1,t=mid;
    }
    p=search(1,L,R,t+1);
    PR((x-p.second-1)/t+1+p.first);



int f[201][201][1001];
int n,m,Q;


void deal1()
{
    int i;
    FOR1(i,m) RD(d[i]),sum[i]=sum[i-1]+d[i];
    build(1,1,m);
    int x1,y1,x2,y2,S;
    while(Q--)
    {
        RD(x1,y1); RD(x2,y2); RD(S);
        cal(y1,y2,S);
    }
}


int get(int x1,int y1,int x2,int y2,int t)
{
    return f[x2][y2][t]-f[x2][y1-1][t]-f[x1-1][y2][t]+f[x1-1][y1-1][t];
}


void deal2()
{
    int i,j,k,x;
    FOR1(i,n) FOR1(j,m) 
    {
        RD(x);
        FOR1(k,1000) f[i][j][k]=f[i-1][j][k]+f[i][j-1][k]-f[i-1][j-1][k];
        f[i][j][x]++;
    }
    int x1,y1,x2,y2,S;
    int cnt,sum,temp;
    while(Q--)
    {
        RD(x1,y1); RD(x2,y2); RD(S);
        sum=0; cnt=0;
        for(i=1000;i>=1;i--)
        {
            temp=get(x1,y1,x2,y2,i);
            if(sum+temp*i<S) sum+=temp*i,cnt+=temp;
            else
            {
                cnt+=(S-sum-1)/i+1;
                break;
            }
        }
        if(i>=1) PR(cnt);
        else puts("Poor QLW");
    }
}


int main()
{
    RD(n,m,Q);
    if(n==1) deal1();
    else deal2();
}

























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值