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