zoukankan      html  css  js  c++  java
  • BZOJ2658-[Zjoi2012]小蓝的好友

    BZOJ2658-[Zjoi2012]小蓝的好友

      题意:

      题解:

        我们可以求出不含任何资源点的矩形的数量,然后用总矩形数减去这个值就是答案。

        首先我们从上往下枚举每一行,来求底部为当前行的矩形数量。然后我们可以维护当前行的每一个点向上最多能延伸多少长。

        然后假设当前状态是这样的(图是从其他人的blog里找到的):

        

        然后我们可以把这个图划分一下:

        

        可以发现所有符合我们要求的矩形的左上角和右上角都在同一个矩形中,然后对于每个矩形统计答案就可以了。

        然后我们就要想办法维护每个矩形。

        我们可以对于当前行每一列最多能向上延伸的距离建一棵笛卡尔树。

        然后我们可以发现,对于每个节点,它代表的矩形的宽度就是它的size,而矩形的高度就是它能向上延伸的距离减去它的父节点能向上延伸的距离。

        然后对于每个节点维护一下能向上延伸的最大距离、它的size和它的子树的答案和。

        对于每次枚举到下一行的时候,我们先将根节点打一个距离+1的tag。

        然后对于该行的每一个资源点,我们都可以将它代表的节点的距离设为0。

        由于要满足笛卡尔树的性质,我们要先把这个点旋到根,然后将距离设为0。旋到根的方法和treap是一样的。

        然后我们就可以统计出答案了。

        由于数据是随机的,所以树的深度是log级别的,复杂度是对的。

    #include<cstdio>
    #include<vector>
    typedef long long ll;
    using namespace std;
    const int maxn=40000;
    int n,r,c,rt; ll ans;
    vector<int> g[maxn+10];
    struct node{
        int ch[2],sz,ht,tag; ll val;
    }a[maxn+10];
    void apply(int p,int v){
        a[p].tag+=v; a[p].ht+=v;
    }
    void update(int p){
        a[p].sz=1; a[p].val=0;
        for(int i=0;i<=1;++i){
            a[p].sz+=a[a[p].ch[i]].sz;
            a[p].val+=a[a[p].ch[i]].val+1ll*a[a[p].ch[i]].sz*(a[a[p].ch[i]].sz+1)*(a[a[p].ch[i]].ht-a[p].ht)/2;
        }
    }
    int build_tree(int l,int r){
        if(l>r) return 0; int mid=l+r>>1;
        a[mid].ch[0]=build_tree(l,mid-1); a[mid].ch[1]=build_tree(mid+1,r);
        update(mid); return mid;
    }
    void push_down(int p){
        for(int i=0;i<=1;++i) if(a[p].ch[i]) apply(a[p].ch[i],a[p].tag);
        a[p].tag=0;
    }
    void rotate(int &p,int d){
        int q=a[p].ch[d]; a[p].ch[d]=a[q].ch[d^1]; a[q].ch[d^1]=p;
        update(p); update(q); p=q;
    }
    void change(int &p,int k){
        push_down(p);
        if(k==a[a[p].ch[0]].sz+1){
            a[p].ht=0; update(p); return;
        }else if(k<=a[a[p].ch[0]].sz){
            change(a[p].ch[0],k); rotate(p,0);
        }else{
            change(a[p].ch[1],k-a[a[p].ch[0]].sz-1); rotate(p,1);
        }
    }
    int main(){
        scanf("%d%d%d",&r,&c,&n);
        for(int i=1;i<=n;++i){
            int x,y; scanf("%d%d",&x,&y); g[x].push_back(y);
        }
        ans=1ll*r*(r+1)*c*(c+1)/4; rt=build_tree(1,c);
        for(int i=1;i<=r;++i){
            apply(rt,1);
            for(int j=0;j<g[i].size();++j) change(rt,g[i][j]);
            ans-=a[rt].val+1ll*a[rt].sz*(a[rt].sz+1)*a[rt].ht/2;
        }
        printf("%lld",ans); return 0;
    }
  • 相关阅读:
    cocos2dx实现浏览图片的功能,拖动精灵实现精灵的左右移动,主要实现代码:
    cocos2dx 实现printf 输出结果,方便调试。
    2015.7.31第十六课 sql2(约束、日期、isnull、case、exists、cast\convert、索引、视图、存储过程、触发器、备份与还原)
    万网MSSQL2008数据库使用手册
    Android Metro风格的Launcher开发系列第一篇
    chromium浏览器开发系列第一篇:如何获取最新chromium源码
    [WebKit内核] JavaScriptCore深度解析基础篇(一)字节码生成及语法树的构建详情分析
    android apk 防止反编译技术第二篇运行时修改Dalvik指令
    chromium浏览器开发系列第二篇:如何编译最新chromium源码
    webapp前端开发软键盘与position:fixed为我们带来的不便
  • 原文地址:https://www.cnblogs.com/jxcakak/p/7759775.html
Copyright © 2011-2022 走看看