题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2658

题意:给出一个n*m的格子。某些格子中有障碍。求包含至少一个障碍的矩形有多少个?

思路:我们求空白矩形的个数。

从上到下一行一行计算,每到达一行,计算以该行为底的空白矩形个数。我们只需要知道每列向上延伸的最大距离。

这个可以看做是一棵树

我们只需要记录每个的高度即可。

那么每次增加一行,若整行都没有障碍,则根节点的高度增加1.否则,障碍将树分为若干子树。这个操作可以用fhq treap实现,即通过树的分离和合并实现所有操作。

合并两个子树AB时,要求A的所有元素小于B。或者将A设为B的左孩子,或者将B设为A的右孩子。这个操作比较简单。

对于分离操作,用split(now,x,y,K)表示,将now为根的子树的前K个孩子分离,分开后的两个子树的根分别是x,y

设K=5

分离红色圈住的5个节点,过程如下:

(这个图来自http://hi.baidu.com/wdxertqdtscnwze/item/7b6a9419be7c68cd756a8498)

const int N=100005;

struct node
{
    int c[2],h,det,size;
    i64 ans;

    void add(int x)
    {
        h+=x;
        det+=x;
    }
};

node a[N];
int root;

#define C2(x) ((x)*((x)+1)/2)

void pushUp(int t)
{
    if(!t) return;
    a[t].size=1;
    a[t].ans=0;
    for(int i=0;i<2;i++) if(a[t].c[i])
    {
        int p=a[t].c[i];
        a[t].size+=a[p].size;
        a[t].ans+=a[p].ans;
        a[t].ans+=(i64)(a[p].h-a[t].h)*C2(a[p].size);
    }
}

void pushDown(int t)
{
    if(!t||!a[t].det) return;
    if(a[t].c[0]) a[a[t].c[0]].add(a[t].det);
    if(a[t].c[1]) a[a[t].c[1]].add(a[t].det);
    a[t].det=0;
}

pair<int,int> split(int u,int k)
{
    if(!u) return MP(0,0);
    pushDown(u);
    if(a[a[u].c[0]].size+1<=k)
    {
        k-=a[a[u].c[0]].size+1;
        pair<int,int> tmp=split(a[u].c[1],k);
        a[u].c[1]=tmp.first;
        pushUp(u);
        return MP(u,tmp.second);
    }
    else
    {
        pair<int,int> tmp=split(a[u].c[0],k);
        a[u].c[0]=tmp.second;
        pushUp(u);
        return MP(tmp.first,u);
    }
}

int merge(int u,int v)
{
    if(!u||!v) return u+v;
    pushDown(u);
    pushDown(v);
    if(a[u].h<a[v].h)
    {
        a[u].c[1]=merge(a[u].c[1],v);
        pushUp(u);
        return u;
    }
    else
    {
        a[v].c[0]=merge(u,a[v].c[0]);
        pushUp(v);
        return v;
    }
}

pair<int,int> b[N];
int n,m,K;

int main()
{

    n=myInt();
    m=myInt();
    K=myInt();
    for(int i=1;i<=K;i++)
    {
        b[i].first=myInt();
        b[i].second=myInt();
    }
    sort(b+1,b+K+1);
    for(int i=1;i<=m;i++)
    {
        root=merge(root,i);
        pushUp(root);
    }
    int cur=1;
    i64 ans=(i64)C2(n)*C2(m);

    for(int i=1;i<=n;i++)
    {
        a[root].add(1);
        while(cur<=K&&b[cur].first==i)
        {
            pair<int,int> tmp1=split(root,b[cur].second-1);
            pair<int,int> tmp2=split(tmp1.second,1);
            a[tmp2.first].h=0;
            root=merge(tmp1.first,tmp2.first);
            root=merge(root,tmp2.second);
            cur++;
        }
        ans-=a[root].ans;
        ans-=(i64)a[root].h*C2(a[root].size);
    }
    printf("%lld\n",ans);
}

BZOJ 2658 小蓝的好友的更多相关文章

  1. @bzoj - 2658@ [Zjoi2012]小蓝的好友(mrx)

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事 ...

  2. 【BZOJ2658】[Zjoi2012]小蓝的好友(mrx) 平衡树维护笛卡尔树+扫描线

    [BZOJ2658][Zjoi2012]小蓝的好友(mrx) Description 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的 ...

  3. 洛谷 P2611 [ZJOI2012]小蓝的好友 解题报告

    P2611 [ZJOI2012]小蓝的好友 题目描述 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物--小蓝的好友. 在帮小 ...

  4. 【BZOJ2658】[Zjoi2012]小蓝的好友(mrx) (扫描线,平衡树,模拟)

    题面 终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物--小蓝的好友. 在帮小蓝确定了旅游路线后,小蓝的好友也不会浪费这个难得 ...

  5. bzoj2658: [Zjoi2012]小蓝的好友(mrx)

    太神辣 treap的随机键值竟然能派上用场.. 要用不旋转的treap来进行维护区间信息 #include<cstdio> #include<cstring> #include ...

  6. BZOJ2658 ZJOI2012 小蓝的好友(treap)

    显然转化为求不包含关键点的矩形个数.考虑暴力,枚举矩形下边界,求出该行每个位置对应的最低障碍点高度,对其建笛卡尔树,答案即为Σhi*(slson+1)*(srson+1),即考虑跨过该位置的矩形个数. ...

  7. [ZJOI2012]小蓝的好友

    https://www.luogu.org/problemnew/show/P2611 题解 \(n\times m\)肯定过不去.. 我们把给定的点看做障碍点,考虑先补集转化为求全空矩阵. 然后我们 ...

  8. bzoj 2658

    首先考虑容斥 我们计算出所有没有点在其中的矩形,然后用所有矩形减去这些矩形即可 然后考虑如何计算没有点在其中的矩形 采用扫描线的思想,从上向下一行一行扫,假设我们扫到的行编号是$a$,然后考虑如果左右 ...

  9. P2611-[ZJOI2012]小蓝的好友【Treap,扫描线】

    正题 题目链接:https://www.luogu.com.cn/problem/P2611 题目大意 \(r*c\)的网格上有\(n\)个标记点,然后求有多少个矩形包含至少一个标记点. \(1\le ...

随机推荐

  1. Job类

    当我们在写MapReduce程序的时候,通常,在main函数里,我们会像下面这样做.建立一个Job对象,设置它的JobName,然后配置输入输出路径,设置我们的Mapper类和Reducer类,设置I ...

  2. Ubuntu 13.10 64位 无法 安装 ia32-libs 解决办法

    安装新立德软件包管理器:打开终端,输入以下命令:sudo apt-get install synaptic 打开新立德软件包管理器,选择“设置>软件库” 选择“其他软件 > 添加” 在AP ...

  3. android 项目学习随笔二(引导页 )

    1.引导页 1.定义灰色.红色圆点的shape XML文件 2.定义布局文件,利用相对布局文件定位,利用线性布局加载灰色圆点,imageview加载红色圆点 3.android.support.v4. ...

  4. java对象的序列化与反序列化使用

    1.Java序列化与反序列化  Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程. 2.为什么需要序列化与反序列化 我们知道,当两个进程进 ...

  5. master-slave(主/从)模式

    主从模式 一般来说用在数据库集群比较多,主要是实现读写分离.对于数据库应用而言基本上是读大于写,因此由 Master 服务器负责增.删.改操作,由 Slave 负责读操作(也就是 SELECT),Ma ...

  6. 用PHP判断远程图片(文件)是否存在

    <?php function check_remote_file_exists($url) { $curl = curl_init($url); // 不取回数据 curl_setopt($cu ...

  7. PHP array_count_values() 函数用于统计数组中所有值出现的次数。

    定义和用法 array_count_values() 函数用于统计数组中所有值出现的次数. 本函数返回一个数组,其元素的键名是原数组的值,键值是该值在原数组中出现的次数. 语法 array_count ...

  8. Python包管理工具介绍

    常见的包管理工具及关系 setuptools -->distribute easy_install-->pip 1.distribute distribute是对标准库disutils模块 ...

  9. ECshop中TemplateBeginEditable 和后台编辑讲解

    在ecshop的dwt文件里面经常发现有“<!-- TemplateBeginEditable name="doctitle" -->和<!-- #BeginLi ...

  10. linux crontab定时执行

    #利用crontab定时执行url研究了两种简单方式#一利用lynx访问url yum install lynxservice crond startcrontab -einsert键* * * * ...