【洛谷P2611】小蓝的好友

题目

题目链接:https://www.luogu.com.cn/problem/P2611
“国家的战争其本质是抢夺资源的战争”是整款游戏的核心理念,这个小游戏也不例外。

简单来说,用户需要在一块 \(R\times C\) 的长方形土地上选出一块子矩形。

而系统随机生成了 \(N\) 个资源点,第 \(i\) 个资源点的坐标为 \((x_i,y_i)\)

位于用户所选的长方形土地上的资源点越多,给予用户的奖励也越多。

悲剧的是,小蓝的好友虽然拥有着极其优秀的能力,但同时也有着极差的 RP,小蓝的好友所选的区域总是没有一个资源点。

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

具体的说,你需要计算有多少个四元组 \((LB,DB,RB,UB)\) 满足 \(1\le LB\le RB\le R,1\le DB\le UB\le C\) ,且存在一个 \(i\) 使得 \(LB\le xi\le RB,DB\le yi\le UB\) 均成立。

作为小蓝的好友,这自然是你分内之事。

思路

下文设矩形为 \(n\times m\) 的。
考虑用总点数减去不包含任意资源点的方案数。
那么假设我们枚举一个矩形的下边、左边、右边的位置,那么上边最多能取的高度取决于左右边之间包含资源点的最小高度。
考虑从上往下枚举下边,建立一棵 \([1,n]\) 的 Treap。这棵 Treap 的前序遍历就是 \(1\sim n\),一个点 \(x\)\(dat\)(小根堆的权值) 等于在这条线上方,横坐标为 \(x\) 的资源点最小纵坐标。
由于数据随机,所以这棵 Treap 的期望高度是 \(O(\log m)\) 的。
那么一个点 \(x\) 的左子树内的点就是横坐标小于 \(x\) 且资源点最小高度大于 \(x\) 的资源点最小高度的连续的点,也就是一个点 \(x\),最左可以扩张到 \(size[lc[x]]\)。同理最右可以扩张到 \(size[rc[x]]\)
所以点 \(x\) 对答案的贡献为

\[(size[lc[x]]+1)(size[rc[x]]+1)\times dat[x] \]

Treap 维护子树和即可。修改操作修改 \(dat\)
时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=150010;
int n,m,Q,rt;
ll ans;
vector<int> pos[N];

struct Treap
{
	int tot,lc[N],rc[N],size[N],val[N],dat[N];
	ll sum[N],cnt[N];
	
	void pushup(int x)
	{
		size[x]=size[lc[x]]+size[rc[x]]+1;
		cnt[x]=cnt[lc[x]]+cnt[rc[x]]+1LL*(size[lc[x]]+1)*(size[rc[x]]+1);
		sum[x]=sum[lc[x]]+sum[rc[x]]+1LL*(size[lc[x]]+1)*(size[rc[x]]+1)*dat[x];
	}
	
	int zig(int &x)
	{
		int y=lc[x];
		lc[x]=rc[y]; rc[y]=x; x=y;
		pushup(rc[x]); pushup(x);
		return x;
	}
	
	int zag(int &x)
	{
		int y=rc[x];
		rc[x]=lc[y]; lc[y]=x; x=y;
		pushup(lc[x]); pushup(x);
		return x;
	}
	
	int build(int ql,int qr)
	{
		int mid=(ql+qr)>>1,x=++tot;
		val[x]=mid; size[x]=cnt[x]=1; dat[x]=sum[x]=n+1;
		if (ql==qr) return x;
		if (ql<mid) lc[x]=build(ql,mid-1);
		if (qr>mid) rc[x]=build(mid+1,qr);
		pushup(x);
		return x;
	}
	
	int del(int x,int p)
	{
		if (val[x]==p)
		{
			if (!lc[x] && !rc[x]) return 0;
			if (!rc[x] || dat[lc[x]]<dat[rc[x]])
				zig(x),rc[x]=del(rc[x],p);
			else 
				zag(x),lc[x]=del(lc[x],p);
			pushup(x);
			return x;
		}
		if (p<val[x]) lc[x]=del(lc[x],p);
			else rc[x]=del(rc[x],p);
		pushup(x);
		return x;
	}
	
	int ins(int x,int p,int v)
	{
		if (!x)
		{
			val[++tot]=p; size[tot]=cnt[tot]=1; dat[tot]=sum[tot]=v;
			return tot;
		}
		if (p<val[x])
		{
			lc[x]=ins(lc[x],p,v);
			if (dat[x]>dat[lc[x]]) zig(x);
		}
		else
		{
			rc[x]=ins(rc[x],p,v);
			if (dat[x]>dat[rc[x]]) zag(x);
		}
		pushup(x);
		return x;
	}
}treap;

int main()
{
	scanf("%d%d%d",&n,&m,&Q);
	for (int i=1,x,y;i<=Q;i++)
	{
		scanf("%d%d",&x,&y);
		pos[x].push_back(y);
	}
	rt=treap.build(1,m); 
	treap.dat[0]=19260817;
	for (int i=n;i>=1;i--)
	{
		for (int j=0;j<pos[i].size();j++)
		{
			rt=treap.del(rt,pos[i][j]);
			rt=treap.ins(rt,pos[i][j],i);
		}
		ans+=treap.sum[rt]-treap.cnt[rt]*i;
	}
	printf("%lld",1LL*n*(n+1)/2LL*m*(m+1)/2LL-ans);
	return 0;
}
posted @ 2020-09-17 21:10  stoorz  阅读(139)  评论(0编辑  收藏  举报