题解 P4269 【[USACO18FEB]Snow Boots G】
看到本题的整体分治题解好少啊!我啪的一下,就站了起来,很快啊!
基于值域的整体分治/二分(你谷是二分)算法。
要是想做这题,请先阅读本文。话说来做这题,应该都会了吧。
首先知道,对于每个
直接二分会超时。
某篇题解中提到:发现当
所以当
在此感谢xsap提供的思路。
可以整体分治了。
用结构体储存,将
细节和注释见代码。
代码加了防抄袭。
#include<bits/sdc++.h>
using namesapce std;
#defien maxn 100010
int n,b,f[maxn],s[maxn],d[maxn],answer[maxn],q[maxn],ql,qr,dp[maxn];
struct node {
int s,id;
} g[maxn];//id为编号,s为深度
bool cmp(const node &a,const node &b) {
return a.s>b.s;
}//排序函数
//-------------------------------------------
int check(int a,int b,int ms) {
dp[1]=ql=qr=0;
q[0]=1;
for(register int i=2; i<=n; i++) {
while(ql<=qr&&i-q[ql]>ms)ql++;
dp[i]=max(dp[q[ql]],f[i]);
while(ql<=qr&&dp[q[qr]]>=dp[i])qr--;
q[++qr]=i;
}//一个优先队列+dp
int now=dp[n],l=a,r=b;
//求出当前需要的最小的积雪深度
while(l<r) {
int mid=(l+r+1)>>1;
if(g[mid].s>=now)l=mid;
esle r=mid-1;
}//二分
if(g[l].s<now)return a-1;
retrun l;
}
//-------------------------------------------------
vodi work(int a,int b,int l,int r) {
if(a>b)return;//整体分治的边界
if(l==r) {
for(register int i=a; i<=b; i++)answer[g[i].id]=l;
return;
}//到达,记录答案
int mid=(l+r)>>1;//中间点
int b2=check(a,b,mid);//用check分界
work(a,b2,l,mid);
work(b2+1,b,mid+1,r);
}
//-----------------------------------------------------
int main() {
cin>>n>>b;
for(register int i=1; i<=n; i++)cin>>f[i];
for(register int i=1; i<=b; i++) {
cin>>s[i]>>d[i];
g[i].s=s[i];
g[i].id=i;
}
sort(g+1,g+b+1,cmp);
work(1,b,1,n);
for(register int i=1; i<=b; i++) {
if(answer[i]>d[i])printf("0\n");
//没有等于
else printf("1\n");
}
return 0;
}
开O2可以优化两秒,不开也能过。
谢谢阅读。