[ZJOI2012]小蓝的好友

小蓝的好友

题解

貌似很板的一道题

好吧,由于感觉与以前做过的一些题很像,所以就想到了单调栈。

很显然,我们要求的就是所有全白的格子个数。我们对于每一行,用单调栈维护它每一列这行的白格子高度。

然后就很容易计算出它的所有矩形的方案数,一个O\left(n^{2} \right )的算法就诞生了。

可这明显会TLE。

好吧,我们发现对于每新加的一行,若i处有黑格,就把它赋值为0,否则加1吧。这东西明显还可以用平衡树维护。

于是,加上一个平衡树就是O\left(klogn \right )了,数据是随机的,不卡单调栈。

源码

很好写

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; 
#define int LL
#define gc() getchar()
const int MAXN=4e4+5;
template<typename _T>
inline void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
int r,c,n;
class Tree{
	public:
		int ch[MAXN][2],father[MAXN],root;
		int val[MAXN],sum[MAXN],siz[MAXN];
		void pushup(int rt){
			siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;
			sum[rt]=val[rt]*(siz[ch[rt][0]]+1)*(siz[ch[rt][1]]+1);
			sum[rt]+=sum[ch[rt][0]]+sum[ch[rt][1]];
		}
		#define lson ch[mid][0]
		#define rson ch[mid][1]
		int build(int l,int r){
			if(l>r)return 0;
			if(l==r){siz[l]=1;return l;}int mid=(l+r)>>1;
			lson=build(l,mid-1);if(lson)father[lson]=mid;
			rson=build(mid+1,r);if(rson)father[rson]=mid;
			pushup(mid);return mid;
		}
		int identify(int x){
			return ch[father[x]][1]==x;
		}
		void connect(int f,int x,int d){
			father[x]=f;ch[f][d]=x;
		}	
		void rotate(int rt){
			int p=father[rt];
			int d1=identify(rt);
			//printf("%d %d %d\n",rt,p,d1);
			int d2=identify(p);
			if(root==p)root=rt;
			connect(p,ch[rt][d1^1],d1);
			connect(father[p],rt,d2);
			connect(rt,p,d1^1);
			pushup(p);pushup(rt);
		}
}Tree;
pair<int,int> zy[100005];
int ans;
signed main(){
	read(r);read(c);read(n);
	for(int i=1;i<=n;i++)read(zy[i].first),read(zy[i].second);
	sort(zy+1,zy+n+1);
	Tree.root=Tree.build(1,c);
	int las=1;Tree.val[0]=r+1;
	for(int i=1;i<=n;i++){
		while(las!=zy[i].first)ans+=Tree.sum[Tree.root],las++;
		int now=zy[i].second;Tree.val[now]=zy[i].first;
		while(Tree.val[Tree.father[now]]<Tree.val[now])Tree.rotate(now);
		while(now)Tree.pushup(now),now=Tree.father[now];
	}
	while(las<=r)ans+=Tree.sum[Tree.root],las++;
	printf("%lld\n",ans);
    return 0;
}

谢谢!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值