# BZOJ3711 : [PA2014]Druzyny

f[i]=max(f[j]+1),max(c[j+1],c[j+2],...,c[i-1],c[i])<=i-j<=min(d[j+1],d[j+2],...,d[i-1],d[i])

i从max(c[k]+l,k)开始，决策j一开始的取值范围为[max(l,g[i]),i-c[k]]

j的下限可能也会右移到g[i]，此时有l<=g[i]<=k-1，由于所有更新i的区间[l,k-1]均不相交

[k+c[k],r]分割，对于每一段用线段树区间更新即可

#include<cstdio>
const int N=1000010,M=2097153,P=1000000007,inf=-1000000;
int n,i,j,c[N],d[N],g[N];
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
inline int merge(int a,int b){return c[a]>c[b]?a:b;}
struct Num{
int x,y;
Num(){x=y=0;}
Num(int _x,int _y){x=_x,y=_y;}
inline Num operator+(Num b){
if(x<b.x)return b;
if(x>b.x)return Num(x,y);
return Num(x,(y+b.y)%P);
}
inline Num operator+(int _x){return Num(x+_x,y);}
inline void operator+=(Num b){*this=*this+b;}
}f[N];
struct Node{int c,d;Num f,tag;}T[M];
void build(int x,int a,int b){
if(a==b){
T[x].c=a;
T[x].d=d[a];
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
T[x].c=merge(T[x<<1].c,T[x<<1|1].c);
T[x].d=min(T[x<<1].d,T[x<<1|1].d);
}
void build2(int x,int a,int b){
T[x].tag=Num(inf,0);
if(a==b){
T[x].d=d[a];
T[x].f=f[a];
return;
}
int mid=(a+b)>>1;
build2(x<<1,a,mid),build2(x<<1|1,mid+1,b);
T[x].d=min(T[x<<1].d,T[x<<1|1].d);
T[x].f=T[x<<1].f+T[x<<1|1].f;
}
int askc(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return T[x].c;
int mid=(a+b)>>1;
}
int askd(int x,int a,int b,int c,int d){
if(c>d)return n+1;
if(c<=a&&b<=d)return T[x].d;
int mid=(a+b)>>1;
}
void add(int x,int a,int b,int c,int d,Num p){
if(c<=a&&b<=d){T[x].tag=T[x].tag+p;return;}
int mid=(a+b)>>1;
}
Num askf(int x,int a,int b,int c,int d){
if(c>d)return Num(inf,0);
if(c<=a&&b<=d)return T[x].f;
int mid=(a+b)>>1;
}
int x=1,a=0,b=n,mid;Num t=Num(inf,0);
while(a!=b){
t+=T[x].tag;
mid=(a+b)>>1,x<<=1;
if(c<=mid)b=mid;else a=mid+1,x|=1;
}
return t+T[x].tag;
}
void change(int x,int a,int b,int c,Num p){
if(a==b){T[x].f=p;return;}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p);
T[x].f=T[x<<1].f+T[x<<1|1].f;
}
inline void update(int l,int k,int r){
int i=max(c[k]+l,k);
if(g[i]>=k||i>r)return;
int jl=max(l,g[i]),jr=i-c[k];
for(;i<=k-1+c[k]&&i<=r;i++){
if(g[i]>jl){
if(g[i]>=k)return;
jl=g[i];
}
f[i]+=tmp;
jr++;
if(jr>=jl)tmp+=f[jr]+1;
}
while(i<=r){
if(g[i]>jl){
if(g[i]>=k)return;
jl=g[i];
}
if(t>r){
return;
}
i=t;
}
}
void solve(int l,int r){
if(l==r){
return;
}
solve(l,k-1);
update(l,k,r);
solve(k,r);
}
int main(){
build(1,0,n);
for(i=0;i<=n;i++)d[i]=n+1,f[i]=Num(inf,0);
f[0]=Num(0,1);
for(i=0;i<=n;i++){