題目
考慮從上往下掃,維護一排點分別表示第列已掃過的最低資源點,按這些點的縱座標維護笛卡爾樹,縱座標越低優先級越大,那麼我們的矩形下邊界在掃描線時的答案就是每個點的左範圍右範圍深度的和,維護這一排點需要滿足深度的性質,所以要用來把每個新出現的資源點旋上去,因爲數據隨機,複雜度爲
#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);
}