zoukankan      html  css  js  c++  java
  • 题解:Luogu P6794 [SNOI2020] 水池

    题面

    先观察操作,了解我们要维护什么

    0. i x h

    稍加思考发现将一格水面提升至 (h) 高度会影响到从该格向左到第一个左隔板高于 (h) 以及该格向右到第一个右隔板高于 (h) 的所有格子

    所以为维护此操作,我们要查询上述的最左最右格以及修改被影响部分的水面高度

    自然我们要维护区间左右隔板的最大值来支持线段树上二分查找

    1. i x

    看起来比较复杂,但可以想出一般规律

    这是样例的图,观察一下会发现,相似于 opt.0 ,设原第 x 格高度 (h') ,会影响到从该格向左到第一个左隔板高于 (h') 以及该格向右到第一个右隔板高于 (h') 的所有格子

    而每个格子的最终水面高度是其在拓展方向(向左,向右)前的隔板高度的最大值

    第一个查询于 opt0 相似,第二个修改只要注意递归顺序,记录最值就行

    2. i x h

    直接单点修改即可

    3. i x

    直接单点查询即可


    用可持久化线段树维护

    整理完后发现需要维护的有区间左隔板最值,区间右隔板最值,单点水量即可

    标记共有 3 个,opt0 的覆盖以及 opt1 向左和向右两个标记

    Code(C++):

    #include<bits/stdc++.h>
    #define forn(i,s,t) for(int i=(s);i<=(t);++i)
    using namespace std;
    const int N = 2e5+3,INF = 1e9+7;
    char ch;
    template<typename T>inline void redn(T &ret) {
    	ret=0,ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-48,ch=getchar();
    }
    int n,q,a[N];
    struct PreSegTree {
    	int val[N<<6],L[N<<6],R[N<<6],lmx[N<<6],rmx[N<<6],tag[N<<6]; // tag: 1 cover, 2 left pour , 3 right pour
    	int rt[N],sl;
    	inline int Ads(int pre) {
    		val[++sl] = val[pre],
    		L[sl] = L[pre],R[sl] = R[pre],
    		lmx[sl] = lmx[pre],rmx[sl] = rmx[pre],
    		tag[sl] = tag[pre];
    		return sl;
    	}
    	inline void push_up(int p) {
    		lmx[p] = max(lmx[L[p]],lmx[R[p]]);
    		rmx[p] = max(rmx[L[p]],rmx[R[p]]);
    	}
    	void Bld(int &p,int l,int r) {
    		p = ++sl;
    		if(l == r) {
    			lmx[p] = a[l-1];
    			rmx[p] = a[r];
    			return ;
    		}
    		int mid = l+r >> 1;
    		Bld(L[p],l,mid),Bld(R[p],mid+1,r);
    		push_up(p);
    	}
    	void push_down(int p) {
    		L[p] = Ads(L[p]),R[p] = Ads(R[p]);
    		switch(tag[p]) {
    			case 1: 
    				val[L[p]] = val[R[p]] = val[p];
    				tag[L[p]] = tag[R[p]] = 1;
    				break ;
    			case 2:
    				val[L[p]] = max(val[p],lmx[R[p]]);
    				val[R[p]] = val[p];
    				tag[L[p]] = tag[R[p]] = 2;
    				break ;
    			case 3:
    				val[L[p]] = val[p];
    				val[R[p]] = max(val[p],rmx[L[p]]);
    				tag[L[p]] = tag[R[p]] = 3;
    		}
    		tag[p] = 0;
    	}
    	void Lpour(int &p,int l,int r,int nl,int nr,int &now) {      // opt1 向左
    		p = Ads(p);
    		if(l == nl&&nr == r) {
    			val[p] = now; tag[p] = 2;
    			now = max(now,lmx[p]);
    			return ;
    		}
    		tag[p]&&(push_down(p),0);
    		int mid = nl+nr >> 1;
    		if(r<=mid) Lpour(L[p],l,r,nl,mid,now);
    		else if(l>mid) Lpour(R[p],l,r,mid+1,nr,now);
    		else Lpour(R[p],mid+1,r,mid+1,nr,now),
    			 Lpour(L[p],l,mid,nl,mid,now);
    	}
    	void Rpour(int &p,int l,int r,int nl,int nr,int &now) {       // opt1 向右
    		p = Ads(p);
    		if(l == nl&&nr == r) {
    			val[p] = now; tag[p] = 3;
    			now = max(now,rmx[p]);
    			return ;
    		}
    		tag[p]&&(push_down(p),0);
    		int mid = nl+nr >> 1;
    		if(r<=mid) Rpour(L[p],l,r,nl,mid,now);
    		else if(l>mid) Rpour(R[p],l,r,mid+1,nr,now);
    		else Rpour(L[p],l,mid,nl,mid,now),
    			 Rpour(R[p],mid+1,r,mid+1,nr,now);
    	}
    	int findl(int p,int l,int r,int pos,int tmp) {               // 寻找左端点
    		if(lmx[p] < tmp) return -1;
    		if(l == r) return l;
    		int mid = l+r >> 1,res = -1;
    		tag[p]&&(push_down(p),0);
    		if(pos<=mid) res = findl(L[p],l,mid,pos,tmp);
    		else {
    			res = findl(R[p],mid+1,r,pos,tmp);
    			if(res == -1) 
    				res = findl(L[p],l,mid,pos,tmp);
    		}
    		return res;
    	}
    	int findr(int p,int l,int r,int pos,int tmp) {              // 寻找右端点
                    if(rmx[p] < tmp) return -1;
    		if(l == r) return l;
    		int mid = l+r >> 1,res = -1;
    		tag[p]&&(push_down(p),0);
    		if(pos>mid) res = findr(R[p],mid+1,r,pos,tmp);
    		else {
    			res = findr(L[p],l,mid,pos,tmp);
    			if(res == -1) 
    				res = findr(R[p],mid+1,r,pos,tmp);
    		}
    		return res;
    	}
    	void cover(int &p,int l,int r,int nl,int nr,int k) {         // 覆盖
    		p = Ads(p);
    		if(l == nl && nr == r) {
    			val[p] = k,tag[p] = 1;
    			return ;
    		}
    		int mid = nl+nr >> 1;
    		tag[p]&&(push_down(p),0);
    		if(r<=mid) cover(L[p],l,r,nl,mid,k);
    		else if(l>mid) cover(R[p],l,r,mid+1,nr,k);
    		else cover(L[p],l,mid,nl,mid,k),
    			 cover(R[p],mid+1,r,mid+1,nr,k);
    	}
    	void Chg(int &p,int l,int r,int pos,int k,int opt) {         // 单点修改
    		p = Ads(p);
    		if(l == r) {
    			opt?rmx[p]=k:lmx[p]=k;
    			return ;
    		}
    		tag[p]&&(push_down(p),0);
    		int mid = l+r >> 1;
    		if(pos<=mid) Chg(L[p],l,mid,pos,k,opt);
    		else Chg(R[p],mid+1,r,pos,k,opt);
    		push_up(p);
    	}
    	int Qry(int p,int l,int r,int pos) {                          // 单点查询
    		if(l == r) return val[p];
    		int mid = l+r >> 1;
    		tag[p]&&(push_down(p),0);
    		if(pos<=mid) return Qry(L[p],l,mid,pos);
    		else return Qry(R[p],mid+1,r,pos);
    	}
    }T;
    int main() {
    	redn(n),redn(q);
    	forn(i,1,n-1) redn(a[i]); a[n] = a[0] = INF;
    	T.Bld(T.rt[0],1,n);
    	int opt,h,x,pos,tmp,L,R;
    	forn(i,1,q) {
    		redn(opt),redn(x),redn(pos);
    		if(!(opt&1)) redn(h);
    		T.rt[i] = T.rt[x];
    		switch(opt) {
    			case 0:
    				tmp = T.Qry(T.rt[i],1,n,pos);
    				if(tmp < h) {
    					L = T.findl(T.rt[i],1,n,pos,h);
    					R = T.findr(T.rt[i],1,n,pos,h);
    					T.cover(T.rt[i],L,R,1,n,h);
    				}
    				break ;
    			case 1:
    				tmp = T.Qry(T.rt[i],1,n,pos);
    				L = T.findl(T.rt[i],1,n,pos,tmp);
    				R = T.findr(T.rt[i],1,n,pos,tmp);
    				tmp = 0,T.Lpour(T.rt[i],L,pos,1,n,tmp);
    				tmp = 0,T.Rpour(T.rt[i],pos,R,1,n,tmp);
    				break ;
    			case 2:
    				T.Chg(T.rt[i],1,n,pos+1,h,0);
    				T.Chg(T.rt[i],1,n,pos,h,1);
    				break ;
    			case 3:
    				printf("%d
    ",T.Qry(T.rt[i],1,n,pos));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    零点起飞学Word与Excel高效办公实战与技巧
    C语言核心技术(原书第2版)
    完全精通Nuendo电脑音乐及音频制作:精细操作与实践指南
    1035.找出直系亲属(floyd)
    1033.继续XXX定律
    1034.寻找大富翁
    1032.ZOJ问题
    1029.魔咒词典
    1031.XXX定律
    1028.继续畅通工程
  • 原文地址:https://www.cnblogs.com/Ax-Dea/p/14153009.html
Copyright © 2011-2022 走看看