#平衡树#洛谷 2611 [ZJOI2012]小蓝的好友
题目
在 \(R\times C\) 的矩形中,问有多少个子矩形使得存在一个给定点在其中,
保证点随机,\(R,C\leq 4\times 10^4,n\leq 10^5\)
分析
考虑容斥,用总方案减去不含点的子矩形个数,
枚举上边界,那么左右边界可取的下边界取决于点的高度,
可以发现维护点的高度实际上是在维护一棵笛卡尔树,
方案的统计可以在笛卡尔树上进行,由于带修,直接用平衡树即可
代码
#include
#include
#include
using namespace std;
const int N=100011; typedef long long lll;
struct rec{int x,y;}a[N]; lll ans,w[N],c[N];
int ke[N],siz[N],root,las=1,son[N][2],R,C,n,mx;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
bool cmp(rec x,rec y){return x.xr) return 0;
int mid=(l+r)>>1;
siz[mid]=r-l+1;
son[mid][0]=build(l,mid-1);
son[mid][1]=build(mid+1,r);
return mid;
}
void pup(int now){
siz[now]=siz[son[now][0]]+siz[son[now][1]]+1;
w[now]=w[son[now][0]]+w[son[now][1]]+1ll*ke[now]*(siz[son[now][0]]+1)*(siz[son[now][1]]+1);
}
void Split(int now,int kth,int &fi,int &se){
if (!now) {fi=se=0; return;}
if (kth>siz[son[now][0]]){
fi=now;
Split(son[now][1],kth-siz[son[now][0]]-1,son[now][1],se);
}else{
se=now;
Split(son[now][0],kth,fi,son[now][0]);
}
pup(now);
}
int Merge(int fi,int se){
if (!fi||!se) return fi|se;
if (ke[fi]>ke[se]){
son[fi][1]=Merge(son[fi][1],se);
pup(fi);
return fi;
}else{
son[se][0]=Merge(fi,son[se][0]);
pup(se);
return se;
}
}
void update(int x,int z){
int fi,se,th; Split(root,x-1,fi,se);
Split(se,1,se,th),w[se]=ke[se]=z;
root=Merge(Merge(fi,se),th);
}
int main(){
R=iut(),C=iut(),n=iut(),mx=R>C?R:C;
for (int i=1;i<=mx;++i) c[i+1]=c[i]+i;
for (int i=1;i<=n;++i) a[i]=(rec){iut(),iut()};
sort(a+1,a+1+n,cmp),root=build(1,C);
for (int l=1,r;l<=n;las=a[l].x,l=r){
ans+=(c[a[l].x]-c[las])*c[C+1]-w[root]*(a[l].x-las);
for (r=l;a[r].x==a[l].x;++r) update(a[r].y,a[l].x);
}
ans+=(c[R+1]-c[las])*c[C+1]-w[root]*(R+1-las);
return !printf("%lld",c[R+1]*c[C+1]-ans);
}