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

题目
考虑从上往下扫,维护一排点分别表示第 i i 列已扫过的最低资源点,按这些点的纵坐标维护笛卡尔树,纵坐标越低优先级越大,那么我们的矩形下边界在扫描线时的答案就是每个点的左范围 × \times 右范围 × \times 深度的和,维护这一排点需要满足深度的性质,所以要用 S p a l y Spaly 来把每个新出现的资源点旋上去,因为数据随机,复杂度为 O ( n log n ) O(n\log n)
A C   C o d e \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);
}
发布了640 篇原创文章 · 获赞 97 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/104072171