zoukankan      html  css  js  c++  java
  • 【洛谷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;
    }
    
  • 相关阅读:
    HDU1029 Ignatius and the Princess IV
    UVA11039 Building designing【排序】
    UVA11039 Building designing【排序】
    POJ3278 HDU2717 Catch That Cow
    POJ3278 HDU2717 Catch That Cow
    POJ1338 Ugly Numbers(解法二)
    POJ1338 Ugly Numbers(解法二)
    UVA532 Dungeon Master
    UVA532 Dungeon Master
    POJ1915 Knight Moves
  • 原文地址:https://www.cnblogs.com/stoorz/p/13687692.html
Copyright © 2011-2022 走看看