bzoj2658 [Zjoi2012]小蓝的好友(mrx) 扫描线+treap

Description


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

在帮小蓝确定了旅游路线后,小蓝的好友也不会浪费这个难得的暑假。与小蓝不同,小蓝的好友并不想将时间花在旅游上,而是盯上了最近发行的即时战略游戏——SangoCraft。但在前往通关之路的道路上,一个小游戏挡住了小蓝的好友的步伐。

“国家的战争其本质是抢夺资源的战争”是整款游戏的核心理念,这个小游戏也不例外。简单来说,用户需要在给定的长方形土地上选出一块子矩形,而系统随机生成了N个资源点,位于用户所选的长方形土地上的资源点越多,给予用户的奖励也越多。悲剧的是,小蓝的好友虽然拥有着极其优秀的能力,但同时也有着极差的RP,小蓝的好友所选的区域总是没有一个资源点。

终于有一天,小蓝的好友决定投诉这款游戏的制造厂商,为了搜集证据,小蓝的好友想算出至少包含一个资源点的区域的数量。作为小蓝的好友,这自然是你分内之事。

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

Solution


容易想到答案为总矩形数量-无资源矩形数量,然后我就不会了

考虑用扫描线,我们从上往下求以当前行为下边界的空矩形数量。我们可以建一棵treap,以y坐标作为下标,并把每一列的最大高度作为优先级。由数据随机可知这样建出来treap是期望logn高的。

不难发现这样建出来的treap每一节点都是连续两段的分割线,那么我们就可以单独统计每个节点(即这一列)的贡献,可以看图意会一下
意会

Code


#include <stdio.h>
#include <string.h>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int N=200005;

std:: vector <int> p[N];

struct treeNode {int son[2],fa; LL ans,h,size,tag;} t[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void push_up(int now) {
    t[now].size=t[t[now].son[0]].size+t[t[now].son[1]].size+1;
    t[now].ans=0;
    if (t[now].son[0]) t[now].ans+=t[t[now].son[0]].ans+(t[t[now].son[0]].size+1)*t[t[now].son[0]].size/2LL*(t[t[now].son[0]].h-t[now].h);
    if (t[now].son[1]) t[now].ans+=t[t[now].son[1]].ans+(t[t[now].son[1]].size+1)*t[t[now].son[1]].size/2LL*(t[t[now].son[1]].h-t[now].h);
}

void push_down(int now) {
    if (!t[now].tag) return ;
    LL w=t[now].tag; t[now].tag=0;
    if (t[now].son[0]) {
        t[t[now].son[0]].tag+=w;
        t[t[now].son[0]].h+=w;
    }
    if (t[now].son[1]) {
        t[t[now].son[1]].tag+=w;
        t[t[now].son[1]].h+=w;
    }
}

void rotate(int x) {
    int y=t[x].fa; int z=t[y].fa;
    int k=t[y].son[1]==x;
    t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
    t[x].son[!k]=y; t[y].fa=x;
    t[z].son[t[z].son[1]==y]=x; t[x].fa=z;
    push_up(y); push_up(x);
}

void modify(int &now,int x) {
    push_down(now);
    if (now==x) {
        t[now].h=0; push_up(now);
        return ;
    }
    int k=x>now;
    modify(t[now].son[k],x);
    if (t[t[now].son[k]].h<t[now].h) {
        int tmp=t[now].son[k];
        rotate(t[now].son[k]);
        now=tmp;
    }
    push_up(now);
}

int build_tree(int tl,int tr) {
    int mid=(tl+tr)>>1;
    if (tl<mid) {
        t[mid].son[0]=build_tree(tl,mid-1);
        t[t[mid].son[0]].fa=mid;
    }
    if (mid<tr) {
        t[mid].son[1]=build_tree(mid+1,tr);
        t[t[mid].son[1]].fa=mid;
    }
    push_up(mid);
    return mid;
}

int main(void) {
    // freopen("data.in","r",stdin);
    LL n=read(),m=read(); int T=read();
    LL ans=(n+1)*n/2*(m+1)*m/2;
    rep(i,1,T) {
        int x=read(),y=read();
        p[x].push_back(y);
    }
    int root=build_tree(1,m);
    rep(i,1,n) {
        t[root].tag++; t[root].h++;
        for (int j=0;j<p[i].size();j++) {
            modify(root,p[i][j]);
        }
        LL tmp=(t[root].size+1)*t[root].size/2LL;
        tmp=tmp*t[root].h;
        ans-=t[root].ans+tmp;
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80778168