【洛谷】P5284 [十二省聯考2019]字串問題
阿新 • • 發佈:2020-07-13
我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();} }