[HNOI/AHOI2018]转盘


题解

问题是一个环不方便处理所以我们可以把ta倍长成链
首先可以发现这个东西可以看做是先在初始节点停留若干分钟再花\(n-1\)分钟畅通的走完\(n\)个点
那么从第\(i\)个点开始走第\(n+i-1\)个点这一圈花费的时间就是\(st[i]=max(\sum_{j=i}^{n+i-1}T_j+i-j)+n-1\)
\(A_i=T_i-i\)
那么\(st[i]=max(\sum_{j=i}^{n+i-1}A_j+i)+n-1\)
其实不需要过多的考虑边界问题,因为\(A_j+i\)一定不小于\(A_{n+j}+i\)
所以\(st[i]=max(\sum_{j=i}^{n\times 2}A_j+i)+n-1\)
那么这样就可以用线段树维护了
需要维护一个\(A_i\)的最大值和\(st_i\)的最小值即可
但是每次修改\(A\)都可能会影响一段区间的\(st\)
所以\(pushup\)的时候会比较麻烦,需要考虑右儿子对左儿子的影响
线段树的相关实现具体看代码

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 200005 ;
using namespace std ;

inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}

int n , m , op , lstans ;
int p[M] , tmx[M * 4] , ans[M * 4] ;
/*
tmx[i] 为区间的 T[i] - i 的最大值
ans[i] 为区间的 min( max(T[j] - j) + i ) 

*/

# define ls (now << 1)
# define rs (now << 1 | 1)
int query(int l , int r , int k , int now) { // k为要来取得左边区间答案的tmx值 
    if(l == r) return l + max( tmx[now] , k ) ;
    int mid = (l + r) >> 1 ;
    if( tmx[rs] >= k ) return min( ans[now] , query(mid + 1 , r , k , rs) ) ; // 显然一个点的左儿子所对应的tmx值应该是比右儿子要大的,所以如果右儿子也比ta大,那么就只能继续去递归右子树看看能不能找到比ta小的 ,最终是要返回答案的最小值,所以还要和当前节点的答案取min 
    else return min( k + mid + 1 , query(l , mid , k , ls) ) ; // 如果右儿子的tmx比ta小,那么ta就可以来取得左边的区间的答案,所以直接递归左子树,并且与右子树的最小答案(k+mid+1:因为右子树的最大值小于ta,所以整个右子树的答案都是ta+pos,而mid+1是最小的pos)取min 
}
inline void pushup(int l , int mid , int now) {
    tmx[now] = max( tmx[ls] , tmx[rs] ) ; // tmx更新比较简单 
    ans[now] = query(l , mid , tmx[rs] , ls) ;
/*  由于我们倍长了整个T,所以只需要考虑左区间当开头的情况即可 
	如果也把右区间的答案计入的话,整棵线段树的右半边的更新长度都不到n,更新信息错误 
	所以只需要考虑右边的区间对左边区间的影响即可 
*/
}
void build(int l , int r , int now) {
    if(l == r) {
        tmx[now] = p[l] - l ; 
        ans[now] = p[l] ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    build(l , mid , ls) ; 
	build(mid + 1 , r , rs) ;
    pushup(l , mid , now) ;
}
void change(int x , int l , int r , int now) {
    if(l == r) {
        tmx[now] = p[l] - l ; 
        ans[now] = p[l] ;
        return ;
    }
    int mid = (l + r) >> 1 ;
    if(mid >= x) change(x , l , mid , ls) ;
    else change(x , mid + 1 , r , rs) ;
    pushup(l , mid , now) ;
}
int main() {
    n = read() ; m = read() ; op = read() ;
    for(int i = 1 ; i <= n ; i ++) p[i] = p[n + i] = read() ;
    build(1 , n * 2 , 1) ; lstans = ans[1] + n - 1 ;
    printf("%d\n",lstans) ; int x , y ;
    while(m --) {
        x = read() ^ (op * lstans) ; y = read() ^ (op * lstans) ;
        p[x] = p[n + x] = y ;
        change(x , 1 , n * 2 , 1) ; change(n + x , 1 , n * 2 , 1) ;
        lstans = ans[1] + n - 1 ; printf("%d\n",lstans) ;
    }
    return 0 ;
}
posted @ 2019-04-25 14:02  beretty  阅读(166)  评论(0编辑  收藏  举报