洛谷P6783 【[Ynoi2008]rrusq】 题解

离线询问,从小到大扫描右端点的同时维护左端点的答案。

\(l_i\) 表示第 \(i\) 个点 \((i,p_i)\) 最晚被覆盖到的时间 .

不难发现我们需要对一个点集的 \(l_i\) 进行赋值,同时维护一个关于 \(l_i\) 的后缀和。

对点建出 KDTree , 每次询问在 KDTree 上遍历并打标记,在打标记的同时要把子树内的所有标记收回。因为收回标记对应着打标记,所以复杂度仍然是 \(\Theta(m)\) 次遍历 KDTree 的复杂度 , 即 \(\Theta(m\sqrt n)\) 次打标记/收回标记的操作。

现在我们要完成的问题变成了支持 \(\Theta(m\sqrt n)\) 次单点修改和 \(\Theta(m)\) 次后缀查询的数据结构 , 不难发现可以用 \(\Theta(1)-\Theta(\sqrt m)\) 的分块来实现它。

时间复杂度 \(\Theta(n\sqrt m+m\sqrt n)\) , 空间复杂度 \(\Theta(n+m)\)

code :

const int N = 100005,Q = 1000005;
struct data_structure{ //O(1)-O(sqrt(m))
	int n,m,siz,cur[N],cr[1000],a[N],tag[1000];
	inline void init(int nn){
		int i; n = nn,siz = max(1,(int)sqrt(n)); 
		for (i = 1; i <= n; ++i) cur[i] = (i-1)/siz+1;
		m = cur[n];
		for (i = 1; i <= m; ++i) cr[i] = min(i*siz,n);
	}
	inline void add(int x,int v){ a[x] += v,tag[cur[x]] += v; }
	inline int ask(int x){
		static int tot,i;
		for (tot = 0,i = cur[x] + 1; i <= m; ++i) tot += tag[i];
		for (i = cr[cur[x]]; i >= x; --i) tot += a[i];
		return tot;
	}
}DS;
int n,y[N],v[N];
int m; struct Mat{ int xl,xr,yl,yr; }mat[N];
int q,ql[Q],ans[Q]; vector<int>G[N];
const int V = N<<3;
int id[N],mxx[V],mnx[V],mxy[V],mny[V],sum[V];
inline bool cmp_x(int i,int j){ return i < j; }
inline bool cmp_y(int i,int j){ return y[i] < y[j]; }
#define lc o<<1
#define rc o<<1|1
inline void Build(int o,int l,int r,int d){
	if (l == r){ mxx[o] = mnx[o] = id[l],mxy[o] = mny[o] = y[id[l]],sum[o] = v[id[l]]; return; }
	int mid = l+r>>1;
	if (d) nth_element(id+l,id+mid,id+r+1,cmp_x); else nth_element(id+l,id+mid,id+r+1,cmp_y);
	Build(lc,l,mid,d^1),Build(rc,mid+1,r,d^1);
	mxx[o] = max(mxx[lc],mxx[rc]);
	mnx[o] = min(mnx[lc],mnx[rc]);
	mxy[o] = max(mxy[lc],mxy[rc]);
	mny[o] = min(mny[lc],mny[rc]);
	sum[o] = sum[lc] + sum[rc];
}
int tag[V]; bool is[V];
int xll,xrr,yll,yrr,tim;
inline bool unchk(int o){ return xll > mxx[o] || xrr < mnx[o] || yll > mxy[o] || yrr < mny[o]; }
inline bool chk(int o){ return xll <= mnx[o] && mxx[o] <= xrr && yll <= mny[o] && mxy[o] <= yrr; }
inline bool chkp(int x){ return xll <= x && x <= xrr && yll <= y[x] && y[x] <= yrr; }
inline void clrn(int o){
	if (tag[o]) DS.add(tag[o],-sum[o]),tag[o] = 0;
}
inline void Clr(int o){
	if (!is[o]) return; if (tag[o]) DS.add(tag[o],-sum[o]),tag[o] = 0;
	Clr(lc),Clr(rc),is[o] = 0;
}
inline void down(int o){
	if (tag[o]){
		clrn(lc),tag[lc] = tag[o],is[lc] = 1;
		clrn(rc),tag[rc] = tag[o],is[rc] = 1;
		tag[o] = 0;
	}
}
inline void Add(int o){
	if (!o || unchk(o)) return;
	if (chk(o)){ Clr(o),tag[o] = tim,DS.add(tim,sum[o]),is[o] = 1; return; }
	down(o),Add(lc),Add(rc),is[o] = 1;
}
int main(){
	register int i,j;
	read(n);
	for (i = 1; i <= n; ++i) read(y[i]),read(v[i]),id[i] = i;
	read(m);
	for (i = 1; i <= m; ++i) read(mat[i].xl),read(mat[i].xr),read(mat[i].yl),read(mat[i].yr);
	DS.init(m); 
	read(q);
	for (i = 1; i <= q; ++i) read(ql[i]),read(j),G[j].push_back(i);
	Build(1,1,n,0);
	for (i = 1; i <= m; ++i){
		tim = i,xll = mat[i].xl,xrr = mat[i].xr,yll = mat[i].yl,yrr = mat[i].yr;
		Add(1);
		for (j = 0; j < G[i].size(); ++j) ans[G[i][j]] = DS.ask(ql[G[i][j]]);
	}
	for (i = 1; i <= q; ++i) write(ans[i]),putchar('\n');
	return 0;
}
posted @ 2020-10-09 21:48  srf  阅读(204)  评论(0编辑  收藏  举报