NOI online 2022丹釣戰
阿新 • • 發佈:2022-05-13
看到這麼個東西賽時想用莫隊,但是打假了,所以就有了下面這個不三不四的程式碼
也就是很裸的暴力
void Push(int st,int ed){ for(int i=st;i<=ed;++i){ while(!q.empty()){ Pair tmp=q.back(); if(tmp.a == data[i].a || tmp.b<=data[i].b){ q.pop_back(); } else break; } q.push_back(data[i]); if(q.size()==1)ans++; } } for(int i=1;i<=Q;++i){ que[i].l=read(),que[i].r=read(),que[i].id=i; } sort(que+1,que+Q+1,cmp); int l=0,r=0; for(int i=1;i<=Q;++i){ if(l<que[i].l){ q=deque<Pair>(),ans=0,l=que[i].l,r=que[i].r; Push(que[i].l,que[i].r); que[i].ans=ans; continue; } if(l==que[i].l){ if(r<que[i].r){ Push(r+1,que[i].r); r=que[i].r; que[i].ans=ans; continue; } if(r==que[i].r){ que[i].ans=ans; continue; } if(r>que[i].r){ q=deque<Pair>(),ans=0,r=que[i].r; Push(que[i].l,que[i].r); que[i].ans=ans; } } } sort(que+1,que+Q+1,cmp1); for(int i=1;i<=Q;++i){ printf("%d\n",que[i].ans); }
對於每一個詢問,\(l\)肯定可以“成功”毋庸置疑。對於\(i\),如果滿足題目中的條件就入棧,否則\(i\)就是成功的。那些可以放進去的點對於答案沒有貢獻,暴力解法的瓶頸就在於遍歷了這些沒有用的點。
我們預處理出每一個點到的下一個"成功"點(初值為\(n+1\)),查詢時從\(l\)到\(r\)一直跳就可以了。
for(int i=1;i<=n;++i){ while(!s.empty() && !(a[i]!=a[s.top()] && b[i]<b[s.top()])){ to[s.top()]=i;s.pop(); } s.push(i); } for(int i=1;i<=q;++i){ int ans=0; int l=read(),r=read(); while(l<=r){ ans++;l=to[l]; } printf("%d\n",ans); }
但是如果所有的點都是成功點,這種演算法會被卡到\(n^2\)。由於是不斷地往後跳可以用倍增優化
for(int i=1;i<=n;++i){ while(!s.empty() && !(a[i]!=a[s.top()] && b[i]<b[s.top()])){ to[s.top()][0]=i;s.pop(); } s.push(i); } for(int i=1;i<=20;++i){ for(int j=1;j<=n;++j){ to[j][i]=to[to[j][i-1]][i-1]; } } for(int i=1;i<=q;++i){ int l=read(),r=read(); for(int j=20;j>=0;--j){ if(to[l][j] && to[l][j]<=r){ l=to[l][j];ans+=(1<<j); } } printf("%d\n",ans); }
民間資料倍增比不加倍增慢了將近一倍...