正解:线段树+单调栈
解题报告:
1551又是一道灵巧连题意都麻油看懂的题,,,,所以先解释一下题意好了,,,,
给定一个n元环
可以从0时刻开始从任一位置出发
每次可以选择向前走一步或者在原地不动
当到第i个点的时间ti>=Ti的时候点i被标记
问标记完整个环最少要多久时间
(Ti带修改QAQ
首先有几个会用到的性质大概港下
1)只要走一圈就足够
试证如下:
可以考虑反过来看这个问题,若现在已知标记的最后一个点的时间为Tim,那么题目就变成辣,现在时间为T,每次可以向后倒退一步或不动,每个点有一个消失时间Ti,必须要在消失时间之前到达这个点
那么显然只要走一圈就足够
(其实直接感性理解一下就好昂,,,显然再走一圈不会更好,,,有什么可证的QAQ
2)肯定选择向前走,在原地是不可能的
不需要证,随便说下趴(其实一样感性理解就很显然昂,,,?
依然反着考虑,现在变成要求Timmin对趴,然后还要在Ti之前到达对趴,那显然肯定一直跑下去昂为什么要停下来,,,所以我jio得我还是在感性理解并麻油理性解释,,,不管了不管了反正就感性理解一下就好辣QAQ
然后通过这两个性质我们就可以得到最优解一定是什么样儿的:
1)只走一圈
2)中途不会停留,就算停留也是在开始停一段时间
(就是说如果在Tim那儿倒叙做的时候发现最后到了起始节点的时候Tim还是有值的那么就要在最初停Tim的时间
综上,可以得到式子Tim=在第一个节点停留的时间Time+n-1
再思考,Time怎么算?想到Time必然满足Time+dis(i,j)>=tj,变形得Time>=tj-j+i,即Time=max(tj-j+i)
然后现在是找一个i使得max(tj-j+i)min
考虑到ti和i都只和i有关且都是定值,设ai表示ti-i
然后就变成了求min(max(aj)+i),其中j<=2*n(本来是j<=i+n嘛,但考虑到j∈[i+n+1,2n]的时候是不可能有贡献的,所以可以扩大范围麻油影响
然后只看这个max(aj)的话就是个后缀最大值,显然能构成一个单调栈
然后对于这个i,其实可以发现,aj是对应的一个区间嘛,那既然要min所以就i是这个区间的左端点,也就是说会是一个定值
所以如果考虑麻油修改的话就是从后往前维护一个单调栈
有修改就用线段树维护一下就好,实现比较简单,具体可以看楼房重建这道题,都差不多,依然是求mx,然后lth变成了存最左端点的区间的答案而已,实现方法以及思想什么的还是比较一致的w
#include<bits/stdc++.h> using namespace std; #define il inline #define rg register #define gc getchar() #define ls(x) (x<<1) #define rs(x) ((x<<1)|1) #define rp(i,x,y) for(rg int i=x;i<=y;++i) const int N=1e5+10,inf=0x7fffffff; int n,m,op,val[N<<1],as; struct sgtr{int l,r,mx,as;}tr[N<<3]; il int read() { char ch=gc;int x=0;bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il int query(int x,int dat) { // printf("1.as=%d\n",tr[1].as); // printf("query : x=%d dat=%d l=%d r=%d\n\n",x,dat,tr[x].l,tr[x].r); if(tr[x].l==tr[x].r)return tr[x].l+dat+1; if(tr[rs(x)].mx<=dat)return query(ls(x),dat); return min(tr[x].as,query(rs(x),dat)); } il void pushup(int x) { // printf("1.as=%d\n",tr[1].as); // printf("pushup : x=%d ls=%d rs=%d mx=%d\n",x,ls(x),rs(x),tr[rs(x)].mx); tr[x].mx=max(tr[ls(x)].mx,tr[rs(x)].mx);tr[x].as=query(ls(x),tr[rs(x)].mx); // printf("pushup x=%d mx=%d\n",x,tr[x].mx); } il void build(int x,int l,int r) { // printf("1.as=%d\n",tr[1].as); // printf("build : x=%d l=%d r=%d\n",x,l,r); tr[x].l=l;tr[x].r=r;tr[x].as=inf; if(l==r)return void(tr[x].mx=val[l]-l); int mid=(l+r)>>1;build(ls(x),l,mid);build(rs(x),mid+1,r);pushup(x); } il void modify(int x,int dat) { // printf("1.as=%d\n",tr[1].as); // printf("modify : x=%d dat=%d\n",x,dat); if(tr[x].l==tr[x].r)return void(tr[x].mx=val[dat]-dat); int mid=(tr[x].l+tr[x].r)>>1;if(mid>=dat)modify(ls(x),dat);else modify(rs(x),dat); pushup(x); } int main() { // freopen("zp.in","r",stdin);freopen("zp.out","w",stdout); n=read();m=read();op=read();rp(i,1,n)val[i]=val[i+n]=read(); build(1,1,n<<1);printf("%d\n",as=tr[1].as+n-1); rp(i,1,m) { int x=read()^(as*op),y=read()^(as*op);val[x]=val[x+n]=y; modify(1,x);modify(1,x+n);printf("%d\n",as=tr[1].as+n-1); } return 0; }