# 【HEOI 2018】制胡窜

YJQ的题解把思路介绍得很明白,只不过有些细节说得还是太笼统了(不过正经的题解就应该这个样子吧).

(以上思路中的公式可能需要一定的微调,具体公式请读者在懂得思路后自行推断.)

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int A=20;
const int N=100010;
const int M=300010;
const int Inf=0x3f3f3f3f;
const double alpha=0.75;
int n,m;
LL ans[M];
char s[N];
struct Q{
int to,next,id;
}q[M];
int mine[N<<1],qt;
inline void add(int x,int y,int z){
q[++qt].to=y,q[qt].next=mine[x],mine[x]=qt,q[qt].id=z;
}
struct V{
int to,next;
}c[N<<1];
}
struct ScapeGoat_Tree{
ScapeGoat_Tree *ch[2];
int size;
int key,max,min;
LL sum1,val1;
int sum2,val2;
inline void pushup(){
size=ch[0]->size+ch[1]->size+1;
sum1=ch[0]->sum1+ch[1]->sum1+val1;
sum2=ch[0]->sum2+ch[1]->sum2+val2;
max=min=key;
max=std::max(max,ch[0]->max);
max=std::max(max,ch[1]->max);
min=std::min(min,ch[0]->min);
min=std::min(min,ch[1]->min);
}
return size*alpha+5<ch[0]->size||size*alpha+5<ch[1]->size;
}
inline void* operator new(size_t);
}*root[N<<1],*null,*C,*mempool,*list[N];
inline void* ScapeGoat_Tree::operator new(size_t){
if(C==mempool){
C=new ScapeGoat_Tree[(1<<15)+10];
mempool=C+(1<<15)+10;
}
return C++;
}
int len;
inline void travel(ScapeGoat_Tree *p){
if(p==null)return;
travel(p->ch[0]);
list[++len]=p;
travel(p->ch[1]);
}
inline ScapeGoat_Tree *divide(int l,int r){
if(l>r)return null;
int mid=(l+r)>>1;
list[mid]->ch[0]=divide(l,mid-1);
list[mid]->ch[1]=divide(mid+1,r);
list[mid]->pushup();
return list[mid];
}
inline void rebuild(ScapeGoat_Tree *&p){
if(p==null)return;
len=0;
travel(p);
p=divide(1,len);
}
inline ScapeGoat_Tree **insert(ScapeGoat_Tree *&p,int key,LL val1,int val2){
if(p==null){
p=new ScapeGoat_Tree;
p->ch[0]=p->ch[1]=null;
p->size=1;
p->key=p->max=p->min=key;
p->sum1=p->val1=val1;
p->sum2=p->val2=val2;
return &null;
}
ScapeGoat_Tree **ret=insert(p->ch[key>p->key],key,val1,val2);
p->pushup();
return ret;
}
inline void Insert(ScapeGoat_Tree *&p,int key,LL val1,int val2){
rebuild(*insert(p,key,val1,val2));
}
inline void update(ScapeGoat_Tree *p,int key){
if(p==null)return;
if(p->key<=key)update(p->ch[1],key);
else{
if(p->ch[0]->size==0||p->ch[0]->max<=key){
p->val1=(LL)p->key*(p->key-key);
p->val2=p->key-key;
}else update(p->ch[0],key);
}
p->pushup();
}
inline int upper_bound(ScapeGoat_Tree *p,int key){
if(p==null)return 0;
if(p->key<=key)return upper_bound(p->ch[1],key);
else{
if(p->ch[0]->size==0||p->ch[0]->max<=key)return p->key;
else return upper_bound(p->ch[0],key);
}
}
inline int lower_bound(ScapeGoat_Tree *p,int key){
if(p==null)return 0;
if(p->key>=key)return lower_bound(p->ch[0],key);
else{
if(p->ch[1]->size==0||p->ch[1]->min>=key)return p->key;
else return lower_bound(p->ch[1],key);
}
}
inline void Insert(ScapeGoat_Tree *&p,int key){
update(p,key);
int pr=lower_bound(p,key);
Insert(p,key,pr?(LL)(key-pr)*key:0,pr?key-pr:0);
}
inline void query(ScapeGoat_Tree *p,int key,LL &sum,int &size){
if(p==null)return;
if(p->key<=key){
sum+=p->ch[0]->sum1+p->val1;
size+=p->ch[0]->sum2+p->val2;
query(p->ch[1],key,sum,size);
}else
query(p->ch[0],key,sum,size);
}
inline LL query(ScapeGoat_Tree *p,int len){
int r1=p->min,rn=p->max,ln=rn-len+1;
LL sum1=0,sum2=0,ret=0;
int size1=0,size2=0;
query(p,r1+len-2,sum1,size1);
query(p,ln,sum2,size2);
if(size1<=size2)ret=0;
else ret=sum1-sum2-(LL)(size1-size2)*ln;
if(ln<r1)ret+=(LL)(r1-len)*(r1-ln);
int prv=lower_bound(p,r1+len-1),nxt=upper_bound(p,prv);
if(!nxt)ret+=(LL)((n-ln-1)+(n-r1))*(r1-ln)>>1;
else ret+=(LL)(r1-(prv-len+1))*std::max(nxt-ln,0);
return ret;
}
inline void dfs(ScapeGoat_Tree *p,ScapeGoat_Tree *&to){
if(p==null)return;
Insert(to,p->key);
dfs(p->ch[0],to);
dfs(p->ch[1],to);
}
#define newnode(a) (max[++sz]=(a),sz)
inline int insert(int x,int last){
int w=last,nw=newnode(max[w]+1),h,nh;
if(!w)
else{
h=trans[w][x];
if(max[h]==max[w]+1)
else{
nh=newnode(max[w]+1);
memcpy(trans[nh],trans[h],40);
}
}
return nw;
}
inline void dfs(int x,int fa){
int i;
f[x][0]=fa;
root[x]=null;
for(i=1;i<A;++i)
f[x][i]=f[f[x][i-1]][i-1];
dfs(c[i].to,x);
}
inline int ipos(int x,int len){
int i;
for(i=A-1;i>=0;--i)
if(max[f[x][i]]>=len)
x=f[x][i];
return x;
}
inline void dfs(int x){
int i,j,v;
v=c[i].to;
dfs(v);
if(root[x]->size<root[v]->size)
std::swap(root[v],root[x]);
dfs(root[v],root[x]);
}
for(i=mine[x];i;i=q[i].next)
ans[q[i].id]=query(root[x],q[i].to);
}
int main(){
rt=newnode(0);
null=new ScapeGoat_Tree;
memset(null,0,sizeof(*null));
null->ch[0]=null->ch[1]=null;
null->min=Inf,null->max=-Inf;
scanf("%d%d",&n,&m);
scanf("%s",s+1);
int i,last=rt,l,r,x;
for(i=1;i<=n;++i)
last=pos[i]=insert(s[i]-'0',last);
for(i=2;i<=sz;++i)
dfs(1,0);
for(i=1;i<=n;++i)
Insert(root[pos[i]],i);
for(i=1;i<=m;++i){
scanf("%d%d",&l,&r);
x=ipos(pos[r],r-l+1);
}