zoukankan      html  css  js  c++  java
  • #RMQ,动态开点线段树#CF803G Periodic RMQ Problem

    题目

    给定(n)个数,将这个数列复制(k)次得到数列(a)
    (a)满足区间赋值操作和区间最小值询问
    (nleq 10^5,qleq 10^5,kleq 10^4即|a|leq 10^9)


    分析

    先考虑线段树的区间赋值和区间最小值询问,如果没有复制那就是基本操作,
    考虑一个很大的变化就是不可能将整棵线段树完全建好,
    考虑动态开点线段树,每当新开一个点时,就先赋值为最小值,
    这样线段树的大小为(O(qlog|a|)),区间赋值和区间最小值照常完成,
    所以问题就转换成快速求未改动时区间最小值,这个用RMQ做就可以了,
    如果该区间长度不短于(n)就直接是原来(n)个数的最小值,
    否则如果这一段跨越了复制点,就维护前缀最小值和后缀最小值拼凑,
    如果区间在一段内直接用RMQ


    代码

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    const int N=100011;
    int f[N][17],two[17],lg[N],pre[N],suf[N],w[N<<6],lazy[N<<6],root,ls[N<<6],rs[N<<6],cnt,n,m;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(int ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline signed min(int a,int b){return a<b?a:b;}
    inline signed RMQ(int l,int r){
    	rr int z=lg[r-l+1];
    	return min(f[l][z],f[r-two[z]+1][z]);
    }
    inline signed answ(int l,int r){
    	if (r-l+1>=n) return pre[n];
    	rr int posl=(l-1)/n+1,posr=(r-1)/n+1;
    	l-=(posl-1)*n,r-=(posr-1)*n;
    	return (posl==posr)?RMQ(l,r):min(suf[l],pre[r]);
    }
    inline void update(int &k,int l,int r,int x,int y,int z){
    	if (!k) w[k=++cnt]=answ(l,r);
    	if (l==x&&r==y) {w[k]=lazy[k]=z; return;}
    	rr int mid=(l+r)>>1;
    	if (lazy[k]){
    		if (!ls[k]) ls[k]=++cnt;
    		if (!rs[k]) rs[k]=++cnt;
    		w[ls[k]]=lazy[ls[k]]=lazy[k],
    		w[rs[k]]=lazy[rs[k]]=lazy[k],
    		lazy[k]=0;
    	}
    	if (y<=mid){
    		if (!rs[k]) w[rs[k]=++cnt]=answ(mid+1,r);
    		update(ls[k],l,mid,x,y,z);
    	}
    	else if (x>mid){
    		if (!ls[k]) w[ls[k]=++cnt]=answ(l,mid);
    		update(rs[k],mid+1,r,x,y,z);
    	}
    	    else update(ls[k],l,mid,x,mid,z),update(rs[k],mid+1,r,mid+1,y,z);
    	w[k]=min(w[ls[k]],w[rs[k]]);
    }
    inline signed query(int &k,int l,int r,int x,int y){
    	if (!k) w[k=++cnt]=answ(l,r);
    	if (l==x&&r==y) return w[k];
    	rr int mid=(l+r)>>1;
    	if (lazy[k]){
    		if (!ls[k]) ls[k]=++cnt;
    		if (!rs[k]) rs[k]=++cnt;
    		w[ls[k]]=lazy[ls[k]]=lazy[k],
    		w[rs[k]]=lazy[rs[k]]=lazy[k],
    		lazy[k]=0;
    	}
    	if (y<=mid) return query(ls[k],l,mid,x,y);
    	else if (x>mid) return query(rs[k],mid+1,r,x,y);
    	    else return min(query(ls[k],l,mid,x,mid),query(rs[k],mid+1,r,mid+1,y));
    } 
    signed main(){
    	n=iut(),m=iut(),lg[0]=-1,two[0]=1,pre[0]=suf[n+1]=1e9+7;
    	for (rr int i=1;i<17;++i) two[i]=two[i-1]<<1;
    	for (rr int i=1;i<=n;++i) f[i][0]=iut(),lg[i]=lg[i>>1]+1;
    	for (rr int i=1;i<=n;++i) pre[i]=min(pre[i-1],f[i][0]);
    	for (rr int i=n;i>=1;--i) suf[i]=min(suf[i+1],f[i][0]);
    	for (rr int j=1;j<=lg[n];++j)
    	for (rr int i=1;i+two[j]-1<=n;++i)
    	    f[i][j]=min(f[i][j-1],f[i+two[j-1]][j-1]);
    	for (rr int T=iut();T;--T){
    		rr int opt=iut(),l=iut(),r=iut();
    		if (opt==1) update(root,1,n*m,l,r,iut());
    		    else print(query(root,1,n*m,l,r)),putchar(10);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Maybe You Don't Know ! 如何比较两个引用是否指向同一个对象?
    记录一点项目心得...
    SharePoint 站点模版
    ObjectSpaces,See you in 2006...
    CLR如何实现线程同步
    Using 1.1, Waiting 2.0 & EasyThread
    在SharePoint中的Workflow引擎开发完成
    ViewState
    《WalkThrough WebPart 入门指南二》完成
    隐藏在.NET中的IoC?
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14911816.html
Copyright © 2011-2022 走看看