bzoj2658[zjoi2012]小蓝的好友(mrx)

Problem 2658. – [Zjoi2012]小蓝的好友(mrx)

2658: [Zjoi2012]小蓝的好友(mrx)

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 404   Solved: 251
[ Submit][ Status][ Discuss]

Description

终于到达了这次选拔赛的最后一题,想必你已经厌倦了小蓝和小白的故事,为了回馈各位比赛选手,此题的主角是贯穿这次比赛的关键人物——小蓝的好友。

在帮小蓝确定了旅游路线后,小蓝的好友也不会浪费这个难得的暑假。与小蓝不同,小蓝的好友并不想将时间花在旅游上,而是盯上了最近发行的即时战略游戏——SangoCraft。但在前往通关之路的道路上,一个小游戏挡住了小蓝的好友的步伐。
“国家的战争其本质是抢夺资源的战争”是整款游戏的核心理念,这个小游戏也不例外。简单来说,用户需要在给定的长方形土地上选出一块子矩形,而系统随机生成了N个资源点,位于用户所选的长方形土地上的资源点越多,给予用户的奖励也越多。悲剧的是,小蓝的好友虽然拥有着极其优秀的能力,但同时也有着极差的RP,小蓝的好友所选的区域总是没有一个资源点。
终于有一天,小蓝的好友决定投诉这款游戏的制造厂商,为了搜集证据,小蓝的好友想算出至少包含一个资源点的区域的数量。作为小蓝的好友,这自然是你分内之事。
 

Input

 每个输入文件中仅包含一个测试数据。
第一行包含两个由空格隔开的正整数R,C,N,表示游戏在一块[1,R]X[1,C]的地图上生成了N个资源点。
     接下来有N行,每行包含两个整数 x,y,表示这个资源点的坐标
(1<=x<=R,1<=Y<=c)。

Output

      输出文件应仅包含一个整数,表示至少包含一个资源点的区域的数量。具体的说,设N个资源点的坐标为(i=1..n),你需要计算有多少个四元组(LB,DB,RB,UB)满足1<=LB<=RB<=R,1<=DB<=UB<=C,且存在一个i使得
LB<=Xi<=RB,DB<=Yi<=UB
均成立

Sample Input

5 5 4
1 2
2 3
3 5
4 1

Sample Output

139

HINT

【数据范围】

对于100%的数据,R,C<=40000,N<=100000,资源点的位置两两不同,且位置为随机生成。

Source

[ Submit][ Status][ Discuss]

HOME Back

分析&&思路:

    刚开始看到这题..什么思路都没有,只有打暴力的想法,不过后来换了个思路,就是全集减去不包含任何一个点的矩形个数。假如一个空白矩阵的长为a,宽为b,那么中间矩形的个数就是 C2a+1C2b+1=a(a+1)/2b(b+1)/2 C a + 1 2 ∗ C b + 1 2 = a ∗ ( a + 1 ) / 2 ∗ b ∗ ( b + 1 ) / 2 ,想到这里之后,我们就可以很自然可以想到记录每个点向上可以延伸的最大距离,和这个矩阵的最大宽度,那就可以做完这道题了。
    至于如何找到这个矩形,我们可以通过treap建立一颗笛卡尔树,每个点存储这个点向上的最大高度h,和这个点可以向左右延伸的最大宽度sz(因为是笛卡尔树所以他的子树size就是最大宽度),还有这个点的ans(不包括这个点的它的子树的贡献)。那么一个点对他的父节点的贡献就是 sz[o]+(sz[o]+1)(h[o]h[f[o]])2 s z [ o ] + ( s z [ o ] + 1 ) ∗ ( h [ o ] − h [ f [ o ] ] ) 2 了,于是答案就很明显了。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=100010;
struct Treap {
    int son[maxn][2],tag[maxn],rt;
    ll ans[maxn],sz[maxn],h[maxn];
    inline void add(int o,int x) {
        h[o]+=x;
        tag[o]+=x;
    }
    inline ll calc(ll x) {
        return x*(x+1)/2;
    }
    inline void update(int o) {
        sz[o]=1,ans[o]=0;
        int x=son[o][0],y=son[o][1];
        if(x) {
            sz[o]+=sz[x];
            ans[o]+=ans[x]+calc(sz[x])*(h[x]-h[o]);
        }
        if(y) {
            sz[o]+=sz[y];
            ans[o]+=ans[y]+calc(sz[y])*(h[y]-h[o]);
        }
    }
    inline void pushdown(int o) {
        if(tag[o]) {
            if(son[o][0])
                add(son[o][0],tag[o]);
            if(son[o][1])
                add(son[o][1],tag[o]);
            update(o);
            tag[o]=0;
        }
    }
    inline void build(int &o,int l,int r) {
        if(l>r) {
            o=0;
            return;
        }
        int mid=(l+r)/2;
        o=mid;
        build(son[o][0],l,mid-1);
        build(son[o][1],mid+1,r);
        update(o);
    }
    inline void rotate(int &o,int z) {
        int y=son[o][z];
        son[o][z]=son[y][z^1];
        son[y][z^1]=o;
        update(o),update(y);
        o=y;
    }
    inline void modify(int &o,int y) {
        pushdown(o);
        if(y==sz[son[o][0]]+1) {
            h[o]=0;
            update(o);
            return;
        }
        if(y<sz[son[o][0]]+1) {
            modify(son[o][0],y);
            rotate(o,0);
        }
        else {
            modify(son[o][1],y-sz[son[o][0]]-1);
            rotate(o,1);
        }
    }
}vvq;
int n,m,c;
vector<int>G[maxn];
ll ans;
int main() {
    read(n),read(m),read(c);
    for(int i=1,u,v;i<=c;i++) {
        read(u),read(v);
        G[u].push_back(v);
    }
    ans=vvq.calc(n)*vvq.calc(m);
    vvq.build(vvq.rt,1,m);
    for(int i=1;i<=n;i++) {
        vvq.add(vvq.rt,1);
        for(unsigned j=0;j<G[i].size();j++)
            vvq.modify(vvq.rt,G[i][j]);
        ans-=vvq.ans[vvq.rt]+vvq.calc(vvq.sz[vvq.rt])*vvq.h[vvq.rt];
    }
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值