「AHOI / HNOI2018」转盘 解题报告
「AHOI / HNOI2018」轉盤
可能是我語文水平不太行...
首先可以猜到一些事實,這個策略一定可以被一個式子表示出來,不然帶修修改個錘子。
然后我們發(fā)現(xiàn),可以枚舉起點,然后直接往前走,如果要等就等到它出現(xiàn)。
因為如果不等,一定要走超過一圈,這樣一定不如從它后面那個點當起點。
既然要等,不如我們就在起點等了,顯然這樣的等價的,于是我們可以搞出這個式子了。
\[ \min_{i=1}^n(\max_{j=i}^{i+n-1}S_j-j+i)+n-1 \]
這里我們把\(S\)倍長了
稍微放縮一下并扔掉不重要的東西,我們要維護的大概是這個東西
\[ \min_{i=1}^ni+(\max_{j=i}^{2n}T_j) \]
我們每次修改\(T_j\),然后詢問這個式子的值
考慮對\(j\)枚舉\(i\),有一些事實是
如果\(T_{p_1},T_{p_2},T_{p_3},\dots,T_{p_k}\)是\(T\)的后綴最大值集合
我們的答案就是
\[ \min_{i=1}^kT_i+p_{i-1}+1 \]
后綴最大值可以以單調棧的形式表示出來
考慮在線段樹上維護
比如說,我們可以
我們每個節(jié)點維護一個右兒子最大值與左兒子整個后綴最大值集合連接成的答案集合。
有點抽象,舉個例子就是
比如有這樣的\(T\)值
左兒子:5 4 3 1 右兒子:2 1 0
那么這個信息就是5 4 3 2這個集合的答案
也不一定非要這樣,但是這樣蠻方便的
維護這個信息得去左兒子上二分,所以這樣是\(\log^2 n\)的
這個題,你發(fā)現(xiàn),\(2n\)的區(qū)間中,右兒子內部不能產(chǎn)生貢獻(因為式子中\(\min\)的枚舉范圍是\(1\sim n\)的)
所以維護一下長為\(n\)的區(qū)間的答案,每次詢問的時候在\((n+1)\sim 2n\)里面找個最大值去問就可以了,注意到這個東西它可以從\(1\sim n\)的最大值里面獲得
Code:
#include <cstdio> #include <cctype> #include <vector> #include <algorithm> using std::min; using std::max; const int SIZE=1<<21; char ibuf[SIZE],*iS,*iT; //#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++) #define gc() getchar() template <class T> void read(T &x) {int f=0;x=0;char c=gc();while(!isdigit(c)) f|=c=='-',c=gc();while(isdigit(c)) x=x*10+c-'0',c=gc();if(f) x=-x; } const int N=2e5+10; const int inf=0x3f3f3f3f; int n,m,p,t[N]; int mx[N<<2],yuu[N<<2]; #define ls id<<1 #define rs id<<1|1 int qry(int id,int l,int r,int d) {if(l==r) return mx[id]>d?d+l:inf;int mid=l+r>>1;if(mx[rs]>d) return min(yuu[id],qry(rs,mid+1,r,d));else return qry(ls,l,mid,d); } void updata(int id,int l,int r) {mx[id]=max(mx[ls],mx[rs]);yuu[id]=qry(ls,l,l+r>>1,mx[rs]); } void upd(int id,int l,int r,int p,int d) {if(l==r){mx[id]=d;return;}int mid=l+r>>1;if(p<=mid) upd(ls,l,mid,p,d);else upd(rs,mid+1,r,p,d);updata(id,l,r); } void build(int id,int l,int r) {if(l==r){mx[id]=t[l];yuu[id]=inf;return;}int mid=l+r>>1;build(ls,l,mid),build(rs,mid+1,r);updata(id,l,r); } int main() {read(n),read(m),read(p);for(int i=1;i<=n;i++) read(t[i]),t[i]-=i;build(1,1,n);int ans=qry(1,1,n,mx[1]-n)+n;printf("%d\n",ans);for(int x,y,i=1;i<=m;i++){read(x),read(y);if(p) x^=ans,y^=ans;upd(1,1,n,x,y-x);printf("%d\n",ans=qry(1,1,n,mx[1]-n)+n);}return 0; }2019.5.21
轉載于:https://www.cnblogs.com/butterflydew/p/10902479.html
總結
以上是生活随笔為你收集整理的「AHOI / HNOI2018」转盘 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初识源代码管理工具——GitHab
- 下一篇: 基于 Storyboard 多种方式的页