1. 程式人生 > >bzoj 5254 [Fjwc2018]紅綠燈 (線段樹)

bzoj 5254 [Fjwc2018]紅綠燈 (線段樹)

題目大意:一個wly從家走到學校要經過n個紅綠燈,綠燈持續時間是$g$,紅燈是$r$,所有紅綠燈同時變紅變綠,交通規則和現實中一樣,不能搶紅燈,兩個紅綠燈之間道路的長度是$di$,一共$Q$個詢問,求他在$k$時刻出發到達學校的時間$(Q<=5*10^4)$

終於過了..jdr是真的duliu

搞了半個多下午才看懂題解

首先總路程一定大於等於$\sum d_{i}$,所以求出等紅燈的總時間就行了

紅綠燈的週期是$(g+r)$,所以 超過$g+r$的道路 或者 詢問的時刻$k$ ,直接取模$(g+r)$即可

定義$f[i]$表示第一次在第i個位置停下(被紅燈卡住),然後等變綠以後,再走到終點的路程中,等紅燈

的總時間

如果我們求出了$f[i]$,那麼對於每個詢問,只需要找出在時刻$k$出發,第一個停下的位置就行了

如果在第$i$個位置停下,設下一個停下的位置是$j$,顯然$j$是唯一的

維護一個權值線段樹,值域是$[0,g+r)$,表示在x時刻出發,第一次停下的位置是$a_{x}$,由於是找出第一次停下的位置,所以倒序列舉紅綠燈

如果$x$時刻出發能夠在位置i停下,可得$g<=(x+dis[i])<=g+r-1$,即到達i之後恰好是紅燈

然後把線上段樹內把$x$的可行區間全都修改成$i$

而$f[i]$可以通過線上段樹裡找$-dis[i]$,得到$i$下一個停下的位置$j$

統計答案算一下總路程加上等紅燈的額外時間就行了

權值可能很大需要動態開點

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define NN 101000
 5 #define ll long long 
 6 using namespace std;
 7  
 8  
 9 int n,m,g,r,root;
10 int d[NN];
11 ll dis[NN],f[NN];
12 struct Seg{
13 int tag[NN*50],val[NN*50],ls[NN*50],rs[NN*50
],tot; 14 void pushdown(int rt){ 15 if(!tag[rt]) return; 16 if(!ls[rt]) ls[rt]=++tot; 17 if(!rs[rt]) rs[rt]=++tot; 18 val[ls[rt]]=val[rs[rt]]=tag[rt]; 19 tag[ls[rt]]=tag[rs[rt]]=tag[rt]; 20 tag[rt]=0; 21 } 22 void update(int L,int R,int l,int r,int &rt,int w) 23 { 24 if(!rt) rt=++tot; 25 if(L<=l&&r<=R){tag[rt]=w,val[rt]=w;return;} 26 int mid=(l+r)>>1;pushdown(rt); 27 if(L<=mid) update(L,R,l,mid,ls[rt],w); 28 if(R>mid) update(L,R,mid+1,r,rs[rt],w); 29 //pushup(rt); 30 } 31 int query(int x,int l,int r,int rt) 32 { 33 if(!rt) return 0; 34 if(l==r) return val[rt]; 35 int mid=(l+r)>>1;pushdown(rt); 36 if(x<=mid) return query(x,l,mid,ls[rt]); 37 else return query(x,mid+1,r,rs[rt]); 38 //pushup(rt); 39 } 40 }s; 41 42 int main() 43 { 44 scanf("%d%d%d",&n,&g,&r); 45 const int ma=g+r; 46 ll tot=0; 47 for(int i=1;i<=n+1;i++){ 48 scanf("%d",&d[i]); 49 tot+=d[i];d[i]%=ma; 50 dis[i]=dis[i-1]+d[i]; 51 } 52 ll L,R,w;int x,y; 53 root=1,s.tot=1; 54 for(int i=n;i>=1;i--) 55 { 56 L=((g-dis[i])%ma+ma)%ma; 57 R=((g+r-1-dis[i])%ma+ma)%ma; 58 w=((-dis[i])%ma+ma)%ma; 59 x=s.query(w,0,ma-1,root); 60 f[i]=f[x]+(x?ma-(dis[x]-dis[i])%ma:0); 61 if(L<=R){ 62 s.update(L,R,0,ma-1,root,i); 63 }else{ 64 s.update(0,R,0,ma-1,root,i); 65 s.update(L,ma-1,0,ma-1,root,i); 66 } 67 } 68 int Q; 69 scanf("%d",&Q); 70 for(int q=1;q<=Q;q++) 71 { 72 scanf("%d",&x); 73 y=s.query(x%ma,0,ma-1,root); 74 ll ret; 75 if(!y) ret=x+tot; 76 else ret=tot+f[y]+x+(ma-(x+dis[y])%ma); 77 printf("%lld\n",ret); 78 } 79 return 0; 80 } 81