• [HNOI/AHOI2018]转盘


    一个结论:一定存在一个最优解只走一圈。否则考虑从最后一个结束位置开始一定可以达到相同效果

    画个图,类似是一种斜线感觉

    考虑一个高度贡献的最高点

    对于i开始的连续n个,答案是:max(Tj-j)+i+n-1

    令ai=Ti-i

    断环成链复制一倍,后面的ai只能更小,所以变成后缀:max(aj)+i+n-1

    求ans=min(max(aj)+i+n-1)

    还是不行

    我们反过来考虑一个j会贡献的最小的i

    如果一个j是整个后缀部分的最大值,那么贡献的最小的i就是j前面第一个大于aj的位置

    如果不是,那么没用。

    第一个性质就是单调栈模型了

    线段树维护单调栈

    ans=min(a(p(j))-p(j-1)),注意p(0)=0,并且必须p(j-1)<n

    合并时候:

    右儿子最大值小于c,不管,递归左儿子

    大于c,记录le表示该区间,右儿子最大值开始往左整个前缀贡献的ans,然后取一下,递归右儿子

    回来时候把当前区间的le更新

    看代码更直观

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=200000+5;
    const int inf=0x3f3f3f3f;
    int n,m,typ;
    int a[N];
    struct node{
        int ans,mx;//mx->-0x3f3f3f3f
        int le;
    }t[4*N];
    int pushup(int x,int l,int r,int c){
        if(l==r){
            if(t[x].mx<=c&&l-1<n) return c+l-1;
            else if(t[x].mx>c&&l<n) return c+l;
            return inf;
        }
        if(t[x<<1|1].mx<=c) return pushup(x<<1,l,mid,c);
        return min(t[x].le,pushup(x<<1|1,mid+1,r,c));
    }
    void build(int x,int l,int r){
        if(l==r){
            t[x].mx=a[l];
            if(l-1<n) t[x].ans=a[l]+l-1,t[x].le=l-1;
            else t[x].ans=inf,t[x].le=inf;
            return;
        }
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        t[x].mx=max(t[x<<1].mx,t[x<<1|1].mx);
        t[x].ans=min(t[x].le=pushup(x<<1,l,mid,t[x<<1|1].mx),t[x<<1|1].ans);
        //cout<<" after pushup "<<l<<" "<<r<<" ans "<<t[x].ans<<" le "<<t[x<<1|1].le<<endl;
    }
    void chan(int x,int l,int r,int p,int c){
        if(l==r){
            t[x].mx=a[l];
            if(l-1<n) t[x].ans=a[l]+l-1,t[x].le=l-1;
            else t[x].ans=inf,t[x].le=inf;
            return;
        }
        if(p<=mid) chan(x<<1,l,mid,p,c);
        else chan(x<<1|1,mid+1,r,p,c);
        t[x].mx=max(t[x<<1].mx,t[x<<1|1].mx);
        t[x].ans=min(t[x].le=pushup(x<<1,l,mid,t[x<<1|1].mx),t[x<<1|1].ans);
    }
    int main(){
        rd(n);rd(m);rd(typ);
        for(reg i=1;i<=n;++i){
            rd(a[i]);a[i]=a[i]-i;
            a[i+n]=a[i]-n;
        }
        build(1,1,2*n);
        printf("%d
    ",t[1].ans+n);
        int lasans=t[1].ans+n;
        int x,y;
        while(m--){
            rd(x);rd(y);
            if(typ) x^=lasans,y^=lasans;
            a[x]=y-x;
            a[x+n]=y-x-n;
            chan(1,1,2*n,x,y-x);
            chan(1,1,2*n,x+n,y-x);
            printf("%d
    ",lasans=t[1].ans+n);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/2 15:07:28
    */

    思路:

    发现走一圈性质

    断环为链复制一倍,找到i开始的时间,区间max,变成后缀max

    反过来考虑一个点什么时候可能成为贡献ans的一员,单调栈的性质。线段树维护单调栈

    跨区间pushup时候,保留左儿子和跨区间的信息,额外记录le变量

    转化成后缀比区间好一些,考虑后缀max就可以套路地变成贡献了

  • 相关阅读:
    iOS中图片与视频一次性多选
    UIImagePickerController Class
    1月16日
    10月20日
    1月14日
    1月13日
    1月12日
    1月11日
    课程评价与建议
    加分总结
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10462102.html
Copyright © 2020-2023  润新知