【洛谷】P5284 [十二省联考2019]字符串问题
我LOJ打不开了我会乱说?
当年愚蠢到用线段树建图的题……
我们首先需要一棵后缀树,根据“正串后缀自动机的fail树是反串的后缀树”,我们反着建一个后缀自动机,并构建正串后缀树
我们可以把要插入的A串或者B串插入到他们在后缀树对应的点,或者在一条边的中间
把A点拆成两个点,中间的边权是A串的长度
找到每个串对应的位置,同一条边上A按照长度顺序穿起来,然后B往自己下面的第一个A连边,这个树变成了一个根为起点的有向图
然后按照支配关系,A的出点往B连边
这个图如果不是DAG,那就是-1,是DAG可以通过dp求出来最长路的大小
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define MAXN 200005
#define fi first
#define se second
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')
typedef long long int64;
using namespace std;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
//-----定义区
char s[MAXN];
int n,na,nb;
struct node {
int nxt,val,to;
}E[MAXN * 20];
int head[MAXN * 5],sumE,sumU;
int A[MAXN],B[MAXN],deg[MAXN * 5];
vector<pair<int,int> > v[MAXN * 2];
int64 dis[MAXN * 5];
queue<int> Q;
//-----
void add(int u,int v,int c) {
E[++sumE].to = v;
E[sumE].nxt = head[u];
E[sumE].val = c;
++deg[v];
head[u] = sumE;
}
struct SAM {
struct node {
int len,par,nxt[26],cnt;
}tr[MAXN * 2];
int tail,last,root,left[MAXN];
int fa[MAXN * 2][21];
void Init() {
tail = 0;
root = last = ++tail;
memset(tr[tail].nxt,0,sizeof(tr[tail].nxt));
tr[tail].len = tr[tail].par = 0;
}
void build(int c) {
int nw = ++tail,p;
memset(tr[nw].nxt,0,sizeof(tr[nw].nxt));
tr[nw].len = tr[last].len + 1;tr[nw].cnt = 1;
left[n - tr[nw].len + 1] = nw;
for(p = last ; p && !tr[p].nxt[c] ; p = tr[p].par) {
tr[p].nxt[c] = nw;
}
if(!p) tr[nw].par = root;
else {
int q = tr[p].nxt[c];
if(tr[q].len == tr[p].len + 1) tr[nw].par = q;
else {
int cq = ++tail;
tr[cq] = tr[q];tr[cq].cnt = 0;
tr[cq].len = tr[p].len + 1;
tr[q].par = tr[nw].par = cq;
for(; p && tr[p].nxt[c] == q ; p = tr[p].par) {
tr[p].nxt[c] = cq;
}
}
}
last = nw;
}
void build_tree() {
for(int i = 1 ; i <= tail ; ++i) {
v[i].clear();
fa[i][0] = tr[i].par;
}
for(int j = 1 ; j <= 18 ; ++j) {
for(int i = 1 ; i <= tail ; ++i) {
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
}
void insert(int l,int r,int id) {
int len = r - l + 1;
int u = left[l];
for(int j = 18 ; j >= 0 ; --j) {
if(tr[fa[u][j]].len >= len) u = fa[u][j];
}
v[u].push_back(make_pair(len,id));
}
}sam;
void build_graph() {
for(int i = 1 ; i <= sam.tail ; ++i) {
//out(i);space;out(sam.tr[i].par);space;out(sam.tr[i].len);enter;
int t = v[i].size();
sort(v[i].begin(),v[i].end());
int p = sam.tr[i].par;
for(int j = 0 ; j < t ; ++j) {
if(v[i][j].se > 200000) {
add(p,A[v[i][j].se - 200000],0);
p = A[v[i][j].se - 200000];
}
}
if(p) add(p,i,0);
p = i;
for(int j = t - 1 ; j >= 0 ; --j) {
if(v[i][j].se <= nb) {
add(B[v[i][j].se],p,0);
}
else p = A[v[i][j].se - 200000];
}
}
}
void Init() {
scanf("%s",s + 1);
n = strlen(s + 1);
memset(dis,0,sizeof(dis));
memset(deg,0,sizeof(deg));
memset(head,0,sizeof(head));
sam.Init();
for(int i = n ; i >= 1 ; --i) {
sam.build(s[i] - 'a');
}
sam.build_tree();
sumE = 0;sumU = sam.tail + 1;
read(na);
for(int i = 1 ; i <= na ; ++i) {
int l,r;
read(l);read(r);
A[i] = sumU;sumU += 2;
add(A[i],A[i] + 1,r - l + 1);
sam.insert(l,r,i + 200000);
}
read(nb);
for(int i = 1 ; i <= nb ; ++i) {
int l,r;read(l);read(r);
B[i] = sumU;sumU++;
sam.insert(l,r,i);
}
--sumU;
int m;read(m);
for(int i = 1 ; i <= m ; ++i) {
int x,y;
read(x);read(y);
add(A[x] + 1,B[y],0);
}
build_graph();
}
void Solve() {
for(int i = 1 ; i <= sumU ; ++i) {
if(deg[i] == 0) {dis[i] = 0;Q.push(i);}
}
int64 ans = 0;
while(!Q.empty()) {
int u = Q.front();Q.pop();
for(int i = head[u] ; i ; i = E[i].nxt) {
int v = E[i].to;--deg[v];
if(dis[v] < dis[u] + E[i].val) {
dis[v] = dis[u] + E[i].val;
}
if(!deg[v]) Q.push(v);
}
ans = max(ans,dis[u]);
}
for(int i = 1 ; i <= sumU ; ++i) {
if(deg[i]) {out(-1);enter;return;}
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
int T;
read(T);
while(T--) {Init();Solve();}
}