1. 程式人生 > 其它 >#線段樹#洛谷 4269 [USACO18FEB]Snow Boots G

#線段樹#洛谷 4269 [USACO18FEB]Snow Boots G

線段樹

題目傳送門


分析

模型轉換一下,能通過當且僅當最長的無法通過段小於 \(d\),(這點應該是此題的精華吧)
那麼按照最大深度從小到大排序,雙指標線上段樹上刪除無法通過段,求最長區間即可


程式碼

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; struct rec{int x,w,rk;}q[N];
int w[N<<2],wl[N<<2],wr[N<<2],a[N],rk[N],ans[N],n,m;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
bool cmp1(int x,int y){return a[x]<a[y];}
bool cmp2(rec x,rec y){return x.x<y.x;}
inline void build(int k,int l,int r){
	w[k]=wl[k]=wr[k]=r-l+1;
	if (l==r) return;
	rr int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}
inline void update(int k,int l,int r,int x){
	if (l==r) {w[k]=wl[k]=wr[k]=0; return;}
	rr int mid=(l+r)>>1;
	if (x<=mid) update(k<<1,l,mid,x);
	    else update(k<<1|1,mid+1,r,x);
	w[k]=max(w[k<<1],w[k<<1|1]);
	w[k]=max(w[k],wr[k<<1]+wl[k<<1|1]);
	wl[k]=wl[k<<1],wr[k]=wr[k<<1|1];
	if (w[k<<1]==mid-l+1) wl[k]+=wl[k<<1|1];
	if (w[k<<1|1]==r-mid) wr[k]+=wr[k<<1];
}
signed main(){
	n=iut(),m=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut(),rk[i]=i;
	for (rr int i=1;i<=m;++i) q[i]=(rec){iut(),iut(),i};
	sort(rk+1,rk+1+n,cmp1),sort(q+1,q+1+m,cmp2),build(1,1,n);
	for (rr int i=1,j=1;i<=m;++i){
		for (;j<=n&&a[rk[j]]<=q[i].x;++j)
		    update(1,1,n,rk[j]);
		if (w[1]<q[i].w) ans[q[i].rk]=1;
	}
	for (rr int i=1;i<=m;++i)
	    putchar(ans[i]+48),putchar(10);
	return 0;
}