BZOJ 2658: [Zjoi2012]小藍的好友(Spaly)

題目
考慮從上往下掃,維護一排點分別表示第ii列已掃過的最低資源點,按這些點的縱座標維護笛卡爾樹,縱座標越低優先級越大,那麼我們的矩形下邊界在掃描線時的答案就是每個點的左範圍×\times右範圍×\times深度的和,維護這一排點需要滿足深度的性質,所以要用SpalySpaly來把每個新出現的資源點旋上去,因爲數據隨機,複雜度爲O(nlogn)O(n\log n)
AC Code\mathrm{AC\ Code}

#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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章