线段树套treap+dp(BZOJ1926)

来源:互联网 发布:站内搜索优化方案 编辑:程序博客网 时间:2024/06/07 15:27

1926: [Sdoi2010]粟粟的书架

Time Limit: 20 Sec  Memory Limit: 552 MB
Submit: 482  Solved: 177
[Submit][Status]

Description

Input

第一行是三个正整数R, C, M。 接下来是一个 R行C 列的矩阵,从上到下、从左向右依次给出了每本书的页数Pi,j。 接下来 M行,第 i 行给出正整数x1i, y1i, x2i, y2i, Hi,表示第i 天的指定区域是﹙x1i, y1i﹚与﹙x2i, y2i﹚间的矩形,总页数之和要求不低于 Hi。 保证 1≤x1i≤x2i≤R,1≤y1i≤y2i≤C。

Output

有M行,第i 行回答粟粟在第 i 天时为摘到苹果至少需要拿取多少本书。如果即使取走所有书都无法摘到苹果,则在该行输出“Poor QLW”(不含引号)。

Sample Input

5 5 7
14 15 9 26 53
58 9 7 9 32
38 46 26 43 38
32 7 9 50 28
8 41 9 7 17
1 2 5 3 139
3 1 5 5 399
3 3 4 5 91
4 1 4 1 33
1 3 5 4 185
3 3 4 3 23
3 1 3 3 108

Sample Output

6
15
2
Poor QLW
9
1
3

HINT

对于 10%的数据,满足 R, C≤10;
对于 20%的数据,满足 R, C≤40;
对于 50%的数据,满足 R, C≤200,M≤200,000;
另有 50%的数据,满足 R=1,C≤500,000,M≤20,000;
对于 100%的数据,满足 1≤Pi,j≤1,000,1≤Hi≤2,000,000,000。



思路:分情况讨论,对于R!=1的来说,用dp递推一下就行了dp[i][j][k],表示坐标(0,0)到(i,j)页数为k的有多少本,查询的时候从最高页数开始暴力就行了

对于R==1的情况则要用树套树进行处理:首先二分页数,然后查询大于等于这个页数的总页数是多少

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=500010;int a[maxn];int R,C,M;int tot;int f[205][205][1005];struct Node{    int ch[2];    int r;//优先级    int v;//值    int s;    int sum;    int cnt;//自身重复次数    void init(int val){v=val;ch[0]=ch[1]=0;s=cnt=1;r=rand();sum=0;}    int cmp(int x)const    {        if(x==v)return -1;        return x<v?0:1;    }}tree[maxn*20];void maintain(int x){    tree[x].s=tree[x].cnt;    tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s;    tree[x].sum=tree[x].cnt*tree[x].v+tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum;}void rotate(int &o,int d){    int k=tree[o].ch[d^1];    tree[o].ch[d^1]=tree[k].ch[d];    tree[k].ch[d]=o;    maintain(o);    maintain(k);    o=k;}void insert(int &o,int x){    if(!o)    {        o=++tot;        tree[o].init(x);    }    else    {        if(x==tree[o].v)tree[o].cnt++;        else        {            int d=(x<tree[o].v?0:1);            insert(tree[o].ch[d],x);            if(tree[tree[o].ch[d]].r>tree[o].r)                rotate(o,d^1);        }    }    maintain(o);}void remove(int &o,int x){    if(!o)return;    int d=tree[o].cmp(x);    if(d==-1)    {        int u=o;        if(tree[o].cnt>1)tree[o].cnt--;        else if(tree[o].ch[0]&&tree[o].ch[1])        {            int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0);            rotate(o,d2);            remove(tree[o].ch[d2],x);        }        else        {            if(!tree[o].ch[0])o=tree[o].ch[1];            else o=tree[o].ch[0];        }    }    else remove(tree[o].ch[d],x);    if(o)maintain(o);}//返回最大值int get_max(int o){    while(tree[o].ch[0])o=tree[o].ch[0];    return tree[o].v;}//返回最小值int get_min(int o){    while(tree[o].ch[1])o=tree[o].ch[1];    return tree[o].v;}//返回val的前驱,如果没有的话返回y//y的初值可赋成0,表示没有前驱int get_pred(int o,int val,int y){    if(!o)return y;    if(tree[o].v<=val)//注意大于等于号        return get_pred(tree[o].ch[1],val,tree[o].v);    else return get_pred(tree[o].ch[0],val,y);}//返回val的后继,如果没有的话返回y//y的初值可赋成0,表示没有后继int get_succ(int o,int val,int y){    if(!o)return y;    if(tree[o].v>=val)return get_succ(tree[o].ch[0],val,tree[o].v);    else return get_succ(tree[o].ch[1],val,y);}//返回第k大的元素的值int get_kth(int o,int k){    if(!o)return 0;    if(k<=tree[tree[o].ch[0]].s)return get_kth(tree[o].ch[0],k);    else if(k>tree[tree[o].ch[0]].s+tree[o].cnt)        return get_kth(tree[o].ch[1],k-tree[tree[o].ch[0]].s-tree[o].cnt);    return tree[o].v;}//返回val的排名int get_rank(int o,int val){    if(!o)return 0;    int lsize=tree[tree[o].ch[0]].s;    if(val<tree[o].v)        return get_rank(tree[o].ch[0],val);    else if(val>tree[o].v)        return get_rank(tree[o].ch[1],val)+lsize+tree[o].cnt;    return lsize+tree[o].cnt;}pair<int,int> getcnt(int o,int val){    if(!o)return make_pair(0,0);    int lsize=tree[tree[o].ch[0]].s;    if(val<tree[o].v)    {        pair<int,int> tmp=getcnt(tree[o].ch[0],val);        tmp.first+=tree[o].cnt+tree[tree[o].ch[1]].s;        tmp.second+=tree[tree[o].ch[1]].sum+tree[o].v*tree[o].cnt;        return tmp;    }    else if(val>tree[o].v)        return getcnt(tree[o].ch[1],val);    int cnt=tree[tree[o].ch[1]].s+tree[o].cnt;    int sum=tree[tree[o].ch[1]].sum+tree[o].v*tree[o].cnt;    return make_pair(cnt,sum);}struct IntervalTree{    int root[maxn<<2];    void build(int o,int l,int r)    {        root[o]=0;        for(int i=l;i<=r;i++)insert(root[o],a[i]);        if(l==r)return;        int mid=(l+r)>>1;        build(o<<1,l,mid);        build(o<<1|1,mid+1,r);    }    pair<int,int> query(int o,int l,int r,int q1,int q2,int val)    {        if(q1<=l&&r<=q2)return getcnt(root[o],val);        int mid=(l+r)>>1;        if(q2<=mid)return query(o<<1,l,mid,q1,q2,val);        if(q1>mid)return query(o<<1|1,mid+1,r,q1,q2,val);        pair<int,int> p,q;        p=query(o<<1,l,mid,q1,mid,val);        q=query(o<<1|1,mid+1,r,mid+1,q2,val);        p.first+=q.first;        p.second+=q.second;        return p;    }}tr;int sum[maxn];void solve1(){    for(int i=1;i<=C;i++)    {        scanf("%d",&a[i]);        sum[i]=sum[i-1]+a[i];    }    int x,x1,y1,x2,y2;    tot=0;    tr.build(1,1,C);    pair<int,int> tmp;    while(M--)    {        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&x);        if(sum[y2]-sum[y1-1]<x)        {            printf("Poor QLW\n");            continue;        }        int l=0,r=1001;        while(l<r)        {            int mid=l+(r-l+1)/2;            tmp=tr.query(1,1,C,y1,y2,mid);            if(tmp.second<x)r=mid-1;            else l=mid;        }        tmp=tr.query(1,1,C,y1,y2,l+1);        printf("%d\n",(x-tmp.second-1)/l+1+tmp.first);    }}int getsum(int x1,int y1,int x2,int y2,int x){    return f[x2][y2][x]-f[x1-1][y2][x]-f[x2][y1-1][x]+f[x1-1][y1-1][x];}void solve2(){    int x,x1,y1,x2,y2,sum;    for(int i=1;i<=R;i++)    {        for(int j=1;j<=C;j++)        {            scanf("%d",&x);            for(int k=1;k<=1000;k++)                f[i][j][k]+=f[i-1][j][k]+f[i][j-1][k]-f[i-1][j-1][k];            f[i][j][x]++;        }    }    while(M--)    {        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&sum);        int cnt=0,ans=0,flag=0;        for(int i=1000;i>0;i--)        {            int tmp=getsum(x1,y1,x2,y2,i);            if(cnt+tmp*i<sum)cnt+=tmp*i,ans+=tmp;            else            {                flag=1;                ans+=(sum-cnt-1)/i+1;                break;            }        }        if(flag)printf("%d\n",ans);        else printf("Poor QLW\n");    }}int main(){    scanf("%d%d%d",&R,&C,&M);    if(R==1)solve1();    else solve2();    return 0;}




0 0
原创粉丝点击