BZOJ2658 [ZJOI2012]小蓝的好友(mrx)

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,资源点的位置两两不同,且位置为随机生成。

题解:

       显然可以补集转化一下,然后考虑枚举上边界。当上边界确定时,可能的区域形成一个直方图。将每一列抽象为点,加入到一颗笛卡尔树中,其中满足堆性质的权值是这一列上矩形的高度,满足二叉搜索树性质的是列的编号。那么以点x为根的子树对答案的贡献ans[x]=ans[lch[x]]+ans[rch[x]]+(dep[fa[x]]-dep[x])*siz[x]*(siz[x]+1)/2。由于数据保证随机,矩形高度这一权值相当于一个随机值,用treap维护即可。

       再考虑当扫描线下移的时候,会出现两个事件:一列的高度加一或者清零。我们先给一行打上一个+1标记。对于清零的点,我们将它放到根,再将dep直接置零即可。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=4e5+10;

namespace Treap {
	
	int tot,root;
	int lch[N],rch[N],dep[N],tag[N],siz[N];
	LL ans[N];
	
	inline LL calc(int fa,int x) {
		return 1ll*(dep[x]-dep[fa])*siz[x]*(siz[x]+1)/2;
	}
	
	inline void inc(int x,int val) {
		tag[x]+=val; dep[x]+=val;
	}
	
	inline void Pushdown(int x) {
		if (!tag[x]) return;
		if (lch[x]) inc(lch[x],tag[x]);
		if (rch[x]) inc(rch[x],tag[x]);
		tag[x]=0;
	}
	
	inline void Pushup(int x) {
		siz[x]=1; ans[x]=0;
		if (lch[x]) siz[x]+=siz[lch[x]],ans[x]+=ans[lch[x]]+calc(x,lch[x]);
		if (rch[x]) siz[x]+=siz[rch[x]],ans[x]+=ans[rch[x]]+calc(x,rch[x]);
	}
	
	int Build(int l,int r) {
		if (l>r) return 0;
		int mid=(l+r)>>1;
		lch[mid]=Build(l,mid-1);
		rch[mid]=Build(mid+1,r);
		Pushup(mid);
		return mid;
	}
	
	int Merge(int x,int y) {
		if (!x||!y) {
			Pushup(x+y);
			return (x+y);
		}
		Pushdown(x); Pushdown(y);
		if (dep[x]<dep[y]) {
			rch[x]=Merge(rch[x],y);
			Pushup(x); return x;
		}
		else {
			lch[y]=Merge(x,lch[y]);
			Pushup(y); return y;
		}
	}
	
	void Split(int now,int k,int &x,int &y) {
		if (!now) return (void) (x=y=0);
		Pushdown(now);
		if (siz[lch[now]]+1<=k) {
			x=now; Split(rch[now],k-siz[lch[now]]-1,rch[now],y);
			Pushup(now);
		}
		else {
			y=now; Split(lch[now],k,x,lch[now]);
			Pushup(now);
		}
	}
	
	LL Query() {
		Pushdown(root);
		return ans[root]+calc(0,root);
	}
}
using namespace Treap;

LL n,m,q,las=1;
LL res=0;
pair<int,int> pnt[N];

void Solve(int row) {
	inc(root,1);
	while (pnt[las].first==row) {
		int x,y,z; 
		Split(root,pnt[las].second-1,x,y);
		Split(y,1,z,y);
		dep[z]=0;
		root=Merge(Merge(x,z),y);
		las++;
	}
	res-=Query();
}

int main() {
	scanf("%lld%lld%lld",&n,&m,&q);
	for (int i=1;i<=q;i++) scanf("%d%d",&pnt[i].first,&pnt[i].second);
	sort(pnt+1,pnt+q+1);
	root=Build(1,m);
	res=1ll*n*(n+1)/2*(m*(m+1)/2);
	for (int i=1;i<=n;i++) Solve(i);
	printf("%lld",res);
	return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值