1. 程式人生 > 實用技巧 >洛谷P6783 【[Ynoi2008]rrusq】 題解

洛谷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;
}