【BZOJ5194】Snow Boots
【原题题面】传送门
【简化题意】
给定一个长度为n的序列。 有m次询问,每次询问给定两个数si,di。你一开始站在0,每次你可以走不超过di,但你到达的位置的数不能超过si。问能否走到n+1。 n,m<=100000。
【未讲之前】不知道这题哪里跟线段树挂钩了,感觉跟线段树八竿子打不着的关系23333。
【题解】先根据s[i]的限制确定出哪些地方是不能走的,然后按s[i]从小到大排序,维护n上不能走的最长连续长度,因为每一次s[i]越来越大,那么限制越来越小。
还有弄清楚只要最长连续不能走的长度小于相应的d[i]就一定能走。这是因为每次能走的长度是1~d[i],所以我可以通过一定的调整使每次面临的都是最长连续长度的困难。
【讲了之后】按照s[i]排序离线这一点没想到哇。还有就是这题的切入口不是怎么线段树,而是理解题意之后想怎么维护不能走的最长连续长度,然后才想到可以用线段树。看网上还有题解说可以用set的,也可以实现的吧。
【具体实现】维护最长连续的长度,需要维护当前结点的范围内最长连续不能走的长度sz。
更新这个值需要max,lmax,rmax;
【code】
#include<bits/stdc++.h> using namespace std; inline int read() { int N=0,C=0;char tf=getchar(); for(;!isdigit(tf);tf=getchar())C|=tf=='-'; for(;isdigit(tf);tf=getchar())N=(N<<1)+(N<<3)+(tf^48); return C?-N:N; } const int N=100010; int n,q,ans[N]; struct nc { int i,s,d;//id step deep friend bool operator <(nc a,nc b){return a.d==b.d?a.s<b.s:a.d<b.d;}//先放砖 nc(int i=0,int s=0,int d=0):i(i),s(s),d(d){} }a[N<<1]; struct tf { int m,l,r,s;//max lmax rmax size }t[N<<2]; void B(int l,int r,int p) { t[p].m=t[p].l=t[p].r=t[p].s=r-l+1; if(l==r)return; int m=l+r>>1; B(l,m,p<<1),B(m+1,r,p<<1|1); } void U(int l,int r,int p,int x) { if(l==r){t[p].m=t[p].l=t[p].r=0;return;} int m=l+r>>1;x<=m?U(l,m,p<<1,x):U(m+1,r,p<<1|1,x); t[p].l=t[p<<1].l==t[p<<1].s?t[p<<1].s+t[p<<1|1].l:t[p<<1].l; t[p].r=t[p<<1|1].r==t[p<<1|1].s?t[p<<1|1].s+t[p<<1].r:t[p<<1|1].r; t[p].m=max(t[p<<1].m,t[p<<1|1].m); t[p].m=max(t[p].m,t[p<<1].r+t[p<<1|1].l); } int main() { n=read(),q=read(),B(1,n,1); for(int i=1,d;i<=n;++i)d=read(),a[i]=nc(i,0,d); for(int i=1,d,s;i<=q;++i)s=read(),d=read(),a[i+n]=nc(i,d,s); sort(a+1,a+n+q+1); for(int i=1;i<=n+q;++i) { if(!a[i].s)U(1,n,1,a[i].i); else ans[a[i].i]=t[1].m<a[i].s; } for(int i=1;i<=q;++i)printf("%d\n",ans[i]); return 0; }
我的代码不知怎么就是调不出来#¥%……&*),上面是豆哥的。
G102的孤儿们都要好好的啊。