标签:names void namespace air fine long div continue freopen
翻转原串,建后缀自动机.
然后先考虑最朴素的思路,找到d所对应的节点,然后一直往上走,并更新答案.
发现由于有a,b的限制,更新答案需要取min,很不爽,不如二分答案.
然后就可以转化为判定性问题,用字符串定位技术找到当前的cd对应的字符串(其实就是倍增+len判定),
判定当前的节点是否有当前a,b范围的right集.
要知道每个节点的right集具体是什么用dfs序建立主席树即可.
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<string>
#include<iomanip>
#include<algorithm>
#include<map>
using namespace std;
#define LL long long
#define FILE "dealing"
#define up(i,j,n) for(int i=j;i<=n;++i)
#define db double
#define ull unsigned long long
#define eps 1e-10
#define pii pair<int,int>
int read(){
int x=0,f=1,ch=getchar();
while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
return f*x;
}
const int maxn=200200,mod=(int)(1e9+7+0.1),limit=(int)(1e6+1);
int n,m;
char s[maxn>>1];
struct node{
int y,next;
}e[maxn<<1];
int len,linkk[maxn],pre[maxn],dfs_clock=0,low[maxn],r[maxn],dep[maxn],fa[maxn][26],id[maxn],zuo[maxn],val[maxn];
void insert(int x,int y){
e[++len].y=y;
e[len].next=linkk[x];
linkk[x]=len;
}
namespace Sam{
int np,p,q,nq,pre[maxn],c[maxn][26],len[maxn],cnt,now,count[maxn],sa[maxn];
int extend(int x){
p=now;now=np=++cnt;len[np]=len[p]+1;
while(p&&!c[p][x])c[p][x]=np,p=pre[p];
if(!p)pre[np]=1;
else {
q=c[p][x];
if(len[q]==len[p]+1)pre[np]=q;
else {
len[nq=++cnt]=len[p]+1;
memcpy(c[nq],c[q],sizeof(c[q]));
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
while(p&&c[p][x]==q)c[p][x]=nq,p=pre[p];
}
}
return np;
}
void build(){
now=1,cnt=1;
up(i,1,n)val[extend(s[i]-‘a‘)]=i;
up(i,1,cnt)zuo[val[i]]=i;
}
void prepare(){
up(i,1,cnt)count[len[i]]++;
up(i,1,cnt)count[i]+=count[i-1];
for(int i=cnt;i>=1;i--)sa[count[len[i]]--]=i;
for(int i=cnt;i>=2;i--)insert(pre[sa[i]],sa[i]),insert(sa[i],pre[sa[i]]);
}
};
namespace chair_man_tree{
const int maxn=3000000;
int c[maxn][2],sum[maxn],root[maxn],n,cnt=0,L,R;
void updata(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]];}
void insert(int x,int& o,int key,int l,int r){
if(key==0){o=x;return;}
o=++cnt;
if(l==r){
sum[o]=sum[x]+1;
return;
}
int mid=(l+r)>>1;
if(key>mid){
c[o][0]=c[x][0];
insert(c[x][1],c[o][1],key,mid+1,r);
}
else {
c[o][1]=c[x][1];
insert(c[x][0],c[o][0],key,l,mid);
}
updata(o);
}
void build(){
up(i,1,n)insert(root[i-1],root[i],r[i],1,n);
}
int query(int x,int o,int l,int r){
//printf("%d %d %d\n",l,r,sum[o]-sum[x]);
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return sum[o]-sum[x];
if(!(sum[o]-sum[x]))return 0;
int mid=(l+r)>>1;
return query(c[x][0],c[o][0],l,mid)+query(c[x][1],c[o][1],mid+1,r);
}
int Query(int l,int r,int Le,int Ri){
L=Le,R=Ri;
//cout<<L<<" "<<R<<endl;
return query(root[l],root[r],1,n);
}
};
void dfs(int x){
pre[x]=++dfs_clock;
//printf("%d %d %d %d\n",x,pre[x],val[x],fa[x][0]);
for(int i=linkk[x];i;i=e[i].next){
if(e[i].y==fa[x][0])continue;
dep[e[i].y]=dep[x]+1;
fa[e[i].y][0]=x;
dfs(e[i].y);
}
low[x]=dfs_clock;
}
bool check(int a,int b,int c,int d){//返回c,d位置是否有right集有a,b的元素
int y=zuo[d];
for(int i=25;i>=0;i--)
if(Sam::len[fa[y][i]]>=c)y=fa[y][i];//定位c,d字符串
int sum=chair_man_tree::Query(pre[y]-1,low[y],a,b);
if(sum)return 1;
else return 0;
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(),m=read();
scanf("%s",s+1);
reverse(s+1,s+n+1);
Sam::build();
Sam::prepare();
dfs(1);
up(i,1,Sam::cnt)id[pre[i]]=i;//主席树对应树
up(i,1,Sam::cnt)r[i]=val[id[i]];
chair_man_tree::n=Sam::cnt;
chair_man_tree::build();
for(int j=1;j<=25;j++)
for(int i=1;i<=Sam::cnt;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
while(m--){
int a=n-read()+1,b=n-read()+1,c=n-read()+1,d=n-read()+1;
swap(a,b);swap(c,d);
int left=1,right=min(d-c+1,b-a+1),ans=0;
while(left<=right){
int mid=(left+right)>>1;
if(check(a+mid-1,b,mid,d))left=mid+1,ans=mid;
else right=mid-1;
}
printf("%d\n",ans);
}
return 0;
}
[bzoj4556] [Tjoi2016&Heoi2016]字符串
标签:names void namespace air fine long div continue freopen
原文地址:http://www.cnblogs.com/chadinblog/p/6522961.html