# 「九省联考 2018」制胡窜

## 题解

### Case 3：

$L_i,R_i$为子串第$i$次出现的左右端点，显然有$R_i=L_i+Len-1$$Len$为串长。

$R_{i}<P_{1}=P_{2}<R_{i+1}$

$R_{i}<P_{1}<P_{2}<R_{i+1}$

$R_{i}<P_{2}<P_{1}<R_{i+1}$

$P_{2} \leq R_{i}<R_{i+1} \leq P_{1}$

$P_{2}<R_{i}<P_{1}<R_{i+1}$

$R_{i}<P_{2}<R_{i+1}<P_{1}$

$R_{i}=P_{2}<P_{1}<R_{i+1}$

$R_{i}<P_{2}<P_{1}=R_{i+1}$

$Min(L_{i+1}-L_{i},R_1-L_i)*(R_{i+1}-L_{m})=Min(R_{i+1}-R_{i},P_1-R_i)*(R_{i+1}-L_{m})$

## 代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int Q=1<<19,P=1<<20;
#define ll long long
int ch[P][10],mx[P],par[P];
int tot=0;
int Push(int val)
{
mx[++tot]=val;
}
int Rt=Push(0),lp=Rt;
int sgn[P];
int include_today_GG=0;
void Sam(int v)
{
int p=lp,np=Push(mx[lp]+1);
for(;p&&(!ch[p][v]);p=par[p])
ch[p][v]=np;
if(!p)par[np]=Rt;
else{
int q=ch[p][v];
if(mx[p]+1==mx[q])par[np]=q;
else{
int nq=Push(mx[p]+1);
for(int i=0;i<10;i++)
ch[nq][i]=ch[q][i];
par[nq]=par[q],par[q]=par[np]=nq;
for(;p&&ch[p][v]==q;p=par[p])
ch[p][v]=nq;
}
}
sgn[np]=++include_today_GG;
lp=np;
}
struct graph{
int inc;
int las[P],e[P],nn[P];
void ins(int x,int y)
{
e[++inc]=y;
nn[inc]=las[x];
las[x]=inc;
}
}tr,qu;
const int S=1<<20;
int POOL[S],toap=0;
struct dt{
int mn,mx;
ll sm;
}w[S];
dt operator+(dt a,dt b)
{return (dt){min(a.mn,b.mn),max(a.mx,b.mx),a.sm+b.sm+((a.mx>=1&&b.mx>=1)?1LL*b.mn*(b.mn-a.mx):0)};}
int ls[S],rs[S];
void Upd(int x)
{w[x]=w[ls[x]]+w[rs[x]];}
int tl=0;
int New()
{
int id=toap?POOL[toap--]:++tl;
w[id]=w[0],ls[id]=rs[id]=0;
return id;
}
void Merge(int &x,int y,int l,int r)
{
if((!x)||(!y)){
if(!x)x=y;
return;
}
int mid=(l+r)>>1;
Merge(ls[x],ls[y],l,mid);
Merge(rs[x],rs[y],mid+1,r);
Upd(x);
POOL[++toap]=y;
}
void Mdf(int &x,int l,int r,int owo)
{
if(!x)x=New();
if(l==r){
w[x].mn=w[x].mx=owo;
return;
}
int mid=(l+r)>>1;
if(owo<=mid)Mdf(ls[x],l,mid,owo);
else Mdf(rs[x],mid+1,r,owo);
Upd(x);
}
dt Gans(int now,int l,int r,int x,int y)
{
if((!now)||(x<=l&&y>=r))return w[now];
int mid=(l+r)>>1;
if(y<=mid)return Gans(ls[now],l,mid,x,y);
if(x>mid)return Gans(rs[now],mid+1,r,x,y);
return Gans(ls[now],l,mid,x,y)+Gans(rs[now],mid+1,r,x,y);
}
int Qian(int now,int l,int r,int x){
if(w[now].mn>=x||(!now))return w[0].mn;
if(l==r)return w[now].mn;
int mid=(l+r)>>1;
if(w[rs[now]].mn<x)return Qian(rs[now],mid+1,r,x);
return Qian(ls[now],l,mid,x);
}
int Hou(int now,int l,int r,int x)
{
if(w[now].mx<=x||(!now))return w[0].mx;
if(l==r)return w[now].mx;
int mid=(l+r)>>1;
if(w[ls[now]].mx>x)return Hou(ls[now],l,mid,x);
return Hou(rs[now],mid+1,r,x);
}
int n;
ll ans[Q];
int rt[P];
#define Qian_(owo) Qian(rt[x],1,n,owo)
#define Hou_(owo) Hou(rt[x],1,n,owo)
ll C2(int x)
{return 1LL*x*(x-1)/2;}
ll GG(int x,int len)
{
ll als=0;
int r1=Hou_(-1),rn=Qian_(n+1);
int l1=r1-len+1,ln=rn-len+1;
int p1=r1+len-1;
int p2=rn-len+1;
if(p1==p2){
int t1=Qian_(p1),t2=Hou_(p2);
if(t1<=n&&t2>=1&&Hou_(t1)==t2)als+=1LL*min(t2-t1,p1-t1)*(t2-ln);
}
if(p1<p2){
int t1=Qian_(p1),t2=Hou_(p2);
if(t1<=n&&t2>=1&&Hou_(t1)==t2)als+=1LL*min(t2-t1,p1-t1)*(t2-ln);
}
if(p2<p1){
int t1=Qian_(p2),t2=Hou_(p1);
if(t1<=n&&t2>=1&&Hou_(t1)==t2)als+=1LL*min(t2-t1,p1-t1)*(t2-ln);
}
if(p2<p1){
int t1=Qian_(p2),t2=Hou_(p1),o;
if(t1<=n&&(o=Hou_(t1))>p2&&o<p1)als+=1LL*min(o-t1,p1-t1)*(o-ln);
if(t2>=1&&(o=Qian_(t2))<p1&&o>p2)als+=1LL*min(t2-o,p1-o)*(t2-ln);
if(t1<=n&&t2>=1&&t1==t2){
if((o=Hou_(t1))>p1)als+=1LL*min(o-t1,p1-t1)*(o-ln);
if((o=Qian_(t1))<p2)als+=1LL*min(t1-o,p1-o)*(t1-ln);
}
int te=Qian_(p1+1);
if(p2<=te&&te<=n){
dt ha=Gans(rt[x],1,n,p2,te-1);
if(ha.mx>=1)als+=1LL*min(te-ha.mx,p1-ha.mx)*(te-ln)+ha.sm-1LL*(ha.mx-ha.mn)*ln;
}
int oo;
if(Hou_(p2-1)==p2){
if((oo=Hou_(p2))>p1)als+=1LL*min(oo-p2,p1-p2)*(p1-ln);
}
if(Qian_(p1+1)==p1){
if((oo=Qian_(p1))<p2)als+=1LL*min(p1-oo,p1-oo)*(p1-ln);
}
}
if(ln<r1){
int del=r1-ln;
als+=1LL*(l1-1)*del;
als+=C2(del)+1LL*(n-r1)*del;
}
return als;
}
int LEN[Q];
void dfs(int x)
{
rt[x]=0;
for(int t=tr.las[x];t;t=tr.nn[t]){
int y=tr.e[t];
dfs(y);
Merge(rt[x],rt[y],1,n);
}
if(sgn[x])
Mdf(rt[x],1,n,sgn[x]);
for(int t=qu.las[x];t;t=qu.nn[t])
ans[qu.e[t]]=C2(n-1)-GG(x,LEN[qu.e[t]]);
}
char s[1<<17];
int SUM[Q];
int fa[1<<18][20];
int main()
{
w[0].mn=998244353,w[0].mx=-998244353;
int q;
scanf("%d%d",&n,&q);
scanf("%s",s+1);
for(int i=1;i<=n;i++)Sam(s[i]-'0'),SUM[i]=lp;
for(int i=1;i<=tot;i++)fa[i][0]=par[i];
for(int j=1;j<=18;j++)
for(int i=1;i<=tot;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=2;i<=tot;i++)
tr.ins(par[i],i);
for(int i=1,l,r;i<=q;i++){
scanf("%d%d",&l,&r);
int x=SUM[r];
LEN[i]=r-l+1;
for(int i=18;i>=0;--i)
if(mx[fa[x][i]]>=r-l+1)x=fa[x][i];
qu.ins(x,i);
}
dfs(1);
for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
return 0;
}

P.S.：感谢chenjingqi大佬帮忙找错

posted @ 2019-02-23 14:56 蒟蒻小果冻 阅读(...) 评论(...)  编辑 收藏