zoukankan      html  css  js  c++  java
  • 洛谷P6783 【[Ynoi2008]rrusq】 题解

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

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

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

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

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

    时间复杂度 (Theta(nsqrt m+msqrt 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('
    ');
    	return 0;
    }
    
  • 相关阅读:
    【WebGoat笔记】 CrossSite Scripting(XSS)
    SQL注入测试工具:Pangolin(穿山甲)
    SQL注入测试工具:Pangolin(穿山甲)
    js取两日期差,包含周六周日?
    CrossSite Scripting(XSS): 跨站脚本攻击介绍
    apmserv虚拟主机不能用set_time_limit(0);
    名称 不是有效的标识符 sql
    最佳的75个安全测试工具
    fzu 1686(DLX 重复点覆盖)
    hdu 3529(DLX)
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13788753.html
Copyright © 2011-2022 走看看