Treap神题。。。首先将问题转化为补集即求不含一个坏点的矩形个数。
考虑这道题目的暴力;显然我们枚举矩形的下边界,得到每一列可以向上拓展多少(视为高度),用单调队列可以求出对于列i向左向右拓展到多少然后就能求出该下边界的答案了。
注意到如果把向左能拓展到的看成是在dfs一颗树时入栈的序号,向右能拓展到的看成是在dfs时出栈的序号,那么显然这可以看成一棵树的dfs序;由于特殊性质可以证明这是一颗二叉树,而且父亲节点的高度总小于儿子的高度。
如果把高度看成键值,这就是一颗Treap的结构!接下来从Treap的角度来看,我们一行一行操作:
首先向下移一行时,相当于直接给所有点高度+1,打标记即可;然后对于这一行的每一个坏点,相当于把它的高度变成0,然后向上旋转(如果改行没有其他0显然是转到根)。
由于数据随机化所以是单次O(logN)的。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define N 40005
#define calc(x) ((ll)(x)*((x)+1)>>1)
using namespace std;
struct node{ int x,y; }a[100005];
int n,m,cnt,rt,sz[N],ht[N],c[N][2],icr[N]; ll sum[N];
bool cmp(const node &u,const node &v){
return u.x<v.x || u.x==v.x && u.y<v.y;
}
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
void maintain(int x){
sz[x]=1; sum[x]=0; int l=c[x][0],r=c[x][1];
if (l){
sz[x]+=sz[l]; sum[x]+=sum[l]+calc(sz[l])*(ht[l]-ht[x]);
}
if (r){
sz[x]+=sz[r]; sum[x]+=sum[r]+calc(sz[r])*(ht[r]-ht[x]);
}
}
void ins(int x,int v){
ht[x]+=v; icr[x]+=v;
}
void pushdown(int x){
if (icr[x]){
ins(c[x][0],icr[x]); ins(c[x][1],icr[x]); icr[x]=0;
}
}
void rotate(int &k,int l){
int t=c[k][l];
c[k][l]=c[t][l^1]; c[t][l^1]=k;
maintain(k); maintain(t); k=t;
}
void mdy(int &k,int x){
pushdown(k); int tmp=sz[c[k][0]]+1;
if (x==tmp){
ht[k]=0; maintain(k); return;
}
if (x<tmp){
mdy(c[k][0],x);
if (ht[c[k][0]]<ht[k]) rotate(k,0); else maintain(k);
} else{
mdy(c[k][1],x-tmp);
if (ht[c[k][1]]<ht[k]) rotate(k,1); else maintain(k);
}
}
void build(int &k,int l,int r){
if (l>r){ k=0; return; }
k=(l+r)>>1;
build(c[k][0],l,k-1); build(c[k][1],k+1,r);
sz[k]=sz[c[k][0]]+sz[c[k][1]]+1;
}
int main(){
m=read(); n=read(); cnt=read(); int i,j;
for (i=1; i<=cnt; i++){
a[i].x=read(); a[i].y=read();
}
sort(a+1,a+cnt+1,cmp);
ll ans=calc(m)*calc(n);
build(rt,1,n);
for (i=j=1; i<=m; i++){
ins(rt,1);
for (; j<=cnt && a[j].x==i; j++) mdy(rt,a[j].y);
ans-=sum[rt]+calc(sz[rt])*ht[rt];
}
printf("%lld\n",ans);
return 0;
}
by lych
2016.5.30