zoukankan      html  css  js  c++  java
  • ! AHOI/HNOI2018转盘


    线段树维护单调栈

    又是一道非常棒的思维题!!!


    SOL:

    问题转化(倒着思考)

    t时刻在某点,每次可以向后走一步或留在原地,然后t减1

    每个点在(T_i)消失,求最小的(t)使得所有点都可以在消失前被访问

    于是惊奇地发现留在原地一定不优,会一直往前走

    破环为链(2倍),对于(iin[n,2n))走到j的时间为(t-(i-j))

    (jin(i-n])满足(t-(i-j)>=T_j o t_{min}=max(T_j-j)+i)

    (ans=min_{iin[n,2n)}(max_{jin(i-n,i]}a_j+i),a_j=T_j-j)

    用i代替i+n-1

    (ans=min_{iin[1,n])}(max_{jin[i,2n]}a_j+i)+n-1)因为(a_i>a_{i+n})

    (a_j)为后缀最大值,i为j前第一个比(a_j)大的位置,(ans=a_j+i+n)

    需要维护一个单调栈

    线段树维护单调栈——楼房重建

    每个区间记录最大值及单调栈长度,合并时左边肯定都是单调栈的内容,右边二分一个位置恰好大于左边分最大值则剩余的加入单调栈,时间复杂度(O(nlog_n^2))

    (p_0,p_1,…,p_k)是栈里留下的元素

    (p_{j-1}<n<=p_j)

    (ans=min_{iin[1,j]}(a_{p_i}+p_{i-1})+n)

    因为((n,2n])里的最大值是([1,n])里的最大值-n,所以只用维护([1,n])

    (mx[p])为区间最大值,(t[p])为区间左半到中间的最小答案

    (ans=query(1,1,n,mx[1]-n))

    时间复杂度(O(nlog_n^2))

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e5+4,inf=1e9;
    int n,m,op,ans,a[N],mx[N<<2],t[N<<2];
    #define lc (p<<1)
    #define rc (p<<1|1)
    int query(int p,int l,int r,int x){
    	if(l==r)return mx[p]>x?x+l:inf;
    	int mid=l+r>>1;
    	return mx[rc]>x?min(t[p],query(rc,mid+1,r,x)):query(lc,l,mid,x);
    }
    inline void pushup(int p,int l,int r){
    	mx[p]=max(mx[lc],mx[rc]);
    	t[p]=query(lc,l,r,mx[rc]);
    }
    void build(int p,int l,int r){
    	if(l==r){
    		mx[p]=a[l]-l;
    		return;
    	}
    	int mid=l+r>>1;
    	build(lc,l,mid);
    	build(rc,mid+1,r);
    	pushup(p,l,mid);
    }
    void modify(int p,int l,int r,int x,int y){
    	if(l==r){
    		mx[p]=y-x;
    		return;
    	}
    	int mid=l+r>>1;
    	if(x<=mid)modify(lc,l,mid,x,y);
    	else modify(rc,mid+1,r,x,y);
    	pushup(p,l,mid);
    }
    int main(){
    	n=read();m=read();op=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	build(1,1,n);
    	ans=query(1,1,n,mx[1]-n)+n;
    	cout<<ans<<"
    ";
    	while(m--){
    		static int x,y;
    		x=read();y=read();
    		if(op){x^=ans;y^=ans;}
    		modify(1,1,n,x,y);
    		ans=query(1,1,n,mx[1]-n)+n;
    		cout<<ans<<"
    ";
    	}
    	return (0-0);
    }
    
  • 相关阅读:
    SQLLoader7(只导入数据文件的其中几行记录)
    SQLLoader6(一个或多个数据文件按条件导入不同的表)
    SQLLoader5(从多个数据文件导入到同一张表)
    SQLLoader4(数据文件中的列与表中列不一致情况-filler)
    SQLLoader3(数据文件没有分隔符时的导入)
    SQLLoader2(导入EXCEL或csv格式的文件)
    SQLLoader1(简单测试,以控制文件方式导入数据)
    可编程内存
    JSONP
    SSL协议
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12604395.html
Copyright © 2011-2022 走看看