可能是我語文水平不太行...
首先可以猜到一些事實,這個策略一定可以被乙個式子表示出來,不然帶修修改個錘子。
然後我們發現,可以列舉起點,然後直接往前走,如果要等就等到它出現。
因為如果不等,一定要走超過一圈,這樣一定不如從它後面那個點當起點。
既然要等,不如我們就在起點等了,顯然這樣的等價的,於是我們可以搞出這個式子了。
\[\min_^n(\max_^s_j-j+i)+n-1
\]這裡我們把\(s\)倍長了
稍微放縮一下並扔掉不重要的東西,我們要維護的大概是這個東西
\[\min_^ni+(\max_^t_j)
\]我們每次修改\(t_j\),然後詢問這個式子的值
考慮對\(j\)列舉\(i\),有一些事實是
如果\(t_,t_,t_,\dots,t_\)是\(t\)的字尾最大值集合
我們的答案就是
\[\min_^kt_i+p_+1
\]字尾最大值可以以單調棧的形式表示出來
比如說,我們可以
我們每個節點維護乙個右兒子最大值與左兒子整個字尾最大值集合連線成的答案集合。
有點抽象,舉個例子就是
比如有這樣的\(t\)值
左兒子:5 4 3 1 右兒子:2 1 0
那麼這個資訊就是5 4 3 2這個集合的答案
也不一定非要這樣,但是這樣蠻方便的
維護這個資訊得去左兒子上二分,所以這樣是\(\log^2 n\)的
這個題,你發現,\(2n\)的區間中,右兒子內部不能產生貢獻(因為式子中\(\min\)的列舉範圍是\(1\sim n\)的)
所以維護一下長為\(n\)的區間的答案,每次詢問的時候在\((n+1)\sim 2n\)裡面找個最大值去問就可以了,注意到這個東西它可以從\(1\sim n\)的最大值裡面獲得
code:
#include #include #include #include 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 void read(t &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)
void updata(int id,int l,int r)
void upd(int id,int l,int r,int p,int d)
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)
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
updata(id,l,r);
}int main()
return 0;
}
2019.5.21 HNOI AHOI2018 轉盤 題解
題目鏈結 好難的題。首先,有等待操作不太好弄。可以發現 在總時間一定的情況下,到每個點越晚越好。所以,可以把所有等待都移到起點處,解不會變差。由於是環,破環為鏈處理。如果在 s 時間在 i 1 i n 出發,那麼到 j i j的時間為 s j i 根據要求,得 s j i t j 即 s max t...
比賽 HNOI2018 轉盤
通過這題,我發現了我最大的缺陷,就是題目中重要的性質發現不了,所以導致後期根本做不了。還是要多做題,培養思維 對於這道題,來發現性質吧 對於每一條路線,因為它有用的就是最終的時刻,所以我們都可以把它變成一條由中間乙個點出發,在起點等待一些時刻,然後接下來的每個時刻都向右走,在同一時刻完成任務 可以知...
C NOIP2018普及級別模擬 字首轉字尾
時間限制 1000 ms 空間限制 262144 kb 具體限制 題目描述 我們現實生活中通常使用中綴表示式,但在計算機裡會用到字首表示式以及字尾表示式,他們的含義如下 字首 先寫運算子,接著是第乙個運算元,最後是第二個運算元 字尾 先寫第乙個運算元,接著寫第二個運算元,最後寫運算子。如中綴表示式3...