题目
考虑从上往下扫,维护一排点分别表示第
列已扫过的最低资源点,按这些点的纵坐标维护笛卡尔树,纵坐标越低优先级越大,那么我们的矩形下边界在扫描线时的答案就是每个点的左范围
右范围
深度的和,维护这一排点需要满足深度的性质,所以要用
来把每个新出现的资源点旋上去,因为数据随机,复杂度为
#include<bits/stdc++.h>
#define maxn 40005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
using namespace std;
int RR,C,n;
vector<int>G[maxn];
int fa[maxn],L[maxn],R[maxn],v[maxn],ch[maxn][2];
LL ans,sm;
#define pa fa[x]
int inr(int x){ return ch[pa][1] == x; }
int isr(int x){ return !fa[x]; }
void upd(int x){
sm -= (R[x]-x+1ll) * (x-L[x]+1ll) * v[x];
L[x]=ch[x][0]?L[ch[x][0]]:x;
R[x]=ch[x][1]?R[ch[x][1]]:x;
sm += (R[x]-x+1ll) * (x-L[x]+1ll) * v[x];
}
void rot(int x){
int y = fa[x] , z = fa[y] , c = inr(x);
if(!isr(y)) ch[z][inr(y)]=x;
(ch[y][c]=ch[x][!c]) && (fa[ch[y][c]] = y);
fa[fa[ch[x][!c]=y]=x]=z;
upd(y);
}
void splay(int x,int N){
for(;!isr(x);rot(x));
upd(x);
sm -= (R[x]-x+1ll) * (x-L[x]+1ll) * v[x];
v[x] = N;
sm += (R[x]-x+1ll) * (x-L[x]+1ll) * v[x];
}
int Build(int l,int r){
if(l>r) return 0;
int m = l+r>>1;
ch[m][0]=Build(l,m-1),ch[m][1]=Build(m+1,r);
fa[ch[m][0]] = fa[ch[m][1]] = m;
upd(m);
return m;
}
int main(){
scanf("%d%d%d",&RR,&C,&n);int x,y;
rep(i,1,n) scanf("%d%d",&x,&y),G[x].push_back(y);
Build(1,C);
rep(i,1,RR){
rep(j,0,G[i].size()-1)
splay(G[i][j],i);
ans += sm;
}
printf("%lld\n",ans);
}