- 思路挺好的,但是证明可以被打表踩爆
每个元素是独立的,如果我们算出一种元素的方案数 那么最终答案就会是
这一步转换比较巧妙,把集合分为每种元素分别处理
考虑递推 ,每次加入最下面一排,那么最下面一排肯定是前缀若干个 1 或是没有 1,枚举个数,这些 1 上面肯定全部都是 1,左边是剩余的三角形,那么
- 如果没有
的限制那么最大最小取到两个端点,可以用分数规划解决
如果有 的限制那么我们会贪心取长度为 的区间
复杂度
- 考场上做着做着就把前缀做成了字符串匹配,所以我来说一下如果是字符串匹配可以怎么做
首先一个在线的做法是我们树剖,然后用线段树维护每个区间的 自动机
这么做的空间是 从空间开始就凉掉了,时间 ,十分不优秀
于是我就考虑不对树上的串建自动机,而是对询问串建 自动机,把树上的串拿过来匹配
于是问题就变成求 树的子树中有没有出现某几种颜色的点,有没有出现某种颜色可以用树剖拆成 个有没有出现 的颜色
一开始想的是 序转换然后用个数颜色的套路,然后发现颜色本身还有个区间的限制,于是树套树?
后来发现用线段树维护颜色集合然后合并上去就可以做了
这么做的复杂度是 - 然后在我写完过后发现求的是一个前缀有没有出现
于是对询问建 ,离线,动态插入一条到根的链的所有字符串
用 的答案减去 的答案,复杂度
AC自动机 + 线段树合并的代码(不知道对不对)
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e5 + 50;
int n, q, fi[N], nxt[N<<1], to[N<<1], tot;
string w[N<<1];
void add(int x, int y, string S){
nxt[++tot] = fi[x], fi[x] = tot;
to[tot] = y; w[tot] = S;
}
string S[N]; int ans[N];
int sz[N],dep[N],fa[N],son[N],in[N],top[N],sgn;
void pre_dfs(int u, int f){
sz[u] = 1;
for(int i = fi[u]; i; i = nxt[i]){
int t = to[i]; if(t == f) continue;
dep[t]=dep[u]+1; fa[t]=u; S[t]=w[i]; pre_dfs(t,u);
sz[u]+=sz[t]; if(sz[t]>sz[son[u]]) son[u]=t;
}
}
void dfs(int u, int tp){
top[u] = tp; in[u]=++sgn;
if(son[u]) dfs(son[u],tp);
for(int i = fi[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa[u] || t == son[u]) continue; dfs(t,t);
}
}
#define pb push_back
struct query{
int l, r, c;
query(int _l=0, int _r=0, int _c=0){ l = _l; r = _r; c = _c; }
};
namespace SGT{
int nd, ls[N], rs[N], sz[N];
#define mid ((l+r)>>1)
void pushup(int x){ sz[x] = sz[ls[x]] + sz[rs[x]]; }
void ins(int &x, int l, int r, int p){
if(!x) x = ++nd; if(l == r){ sz[x] = 1; return; }
if(p<=mid) ins(ls[x],l,mid,p);
else ins(rs[x],mid+1,r,p); pushup(x);
}
void merge(int &x, int y, int l, int r){
if(!x || !y){ x = x|y; return; }
if(l == r){ sz[x] = 1; return; }
merge(ls[x],ls[y],l,mid);
merge(rs[x],rs[y],mid+1,r);
pushup(x);
}
int query(int x, int l, int r, int L, int R){
if(!x) return 0; if(L<=l && r<=R) return sz[x]; int ans = 0;
if(L<=mid) ans+=query(ls[x],l,mid,L,R);
if(R>mid) ans+=query(rs[x],mid+1,r,L,R); return ans;
}
}
namespace AC{
cs int N = ::N * 10;
int ch[N][26], fail[N], nd; vector<query> qry[N];
int ins(char *S){
int len = strlen(S), now = 0;
for(int i = 0; i < len; i++){
int c = S[i]-'a'; if(!ch[now][c]) ch[now][c] = ++nd;
now = ch[now][c];
} return now;
}
vector<int> G[N];
void build(){
queue<int> q;
for(int i = 0; i < 26; i++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = 0; i < 26; i++){
if(!ch[x][i]) ch[x][i] = ch[fail[x]][i];
else fail[ch[x][i]] = ch[fail[x]][i], q.push(ch[x][i]);
}
} for(int i = 1; i <= nd; i++) G[fail[i]].pb(i), cout << fail[i] << endl;
}
vector<int> col[N];
void putcol(string S, int c){
int len = S.length(), now = 0;
for(int i = 0; i < len; i++){
now = ch[now][S[i]-'a'];
col[now].pb(c);
}
}
int rt[N];
void work(int u){
for(int e = 0; e < G[u].size(); e++){
int v = G[u][e]; work(v);
SGT::merge(rt[u],rt[v],1,n);
}
for(int i = 0; i < col[u].size(); i++)
SGT::ins(rt[u],1,n,col[u][i]);
for(int i = 0; i < qry[u].size(); i++){
query now = qry[u][i];
ans[now.c] += SGT::query(rt[u],1,n,now.l,now.r);
}
}
};
void pushqry(int c, int ps, int u, int v){
while(top[u] ^ top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u, v);
AC::qry[ps].pb(query(in[top[u]],in[u],c));
u = fa[top[u]];
}
if(in[u] > in[v]) swap(u,v);
if(in[u] < in[v]) AC::qry[ps].pb(query(in[u]+1,in[v],c));
}
int main(){
n = read(); char s[10];
for(int i = 1, x, y; i < n; i++){
x = read(), y = read(); scanf("%s",s);
string S = s; add(x,y,S); add(y,x,S);
} pre_dfs(1,0); dfs(1,1);
q = read();
for(int i = 1; i <= q; i++){
int u = read(), v = read(); scanf("%s",s);
int nx = AC::ins(s);
pushqry(i, nx, u, v);
}
AC::build();
for(int i = 2; i <= n; i++) AC::putcol(S[i],in[i]);
AC::work(0);
for(int i = 1; i <= q; i++) cout << ans[i] << '\n';
return 0;
}
#include<bits/stdc++.h>
#define pb push_back
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e5 + 50;
int n, q, fi[N], nxt[N<<1], to[N<<1], tot;
string w[N<<1];
void add(int x, int y, string S){
nxt[++tot] = fi[x], fi[x] = tot;
to[tot] = y; w[tot] = S;
}
int ans[N];
struct query{
int u, op, c;
query(int _u=0, int _op=0, int _c=0){ u = _u; op = _op; c = _c; }
}; vector<query> qry[N];
int sz[N],dep[N],son[N],fa[N],top[N];
void pre_dfs(int u, int f){
sz[u] = 1;
for(int i = fi[u]; i; i = nxt[i]){
int t = to[i]; if(t == f) continue;
dep[t]=dep[u]+1; fa[t]=u; pre_dfs(t,u);
sz[u]+=sz[t]; if(sz[t]>sz[son[u]]) son[u]=t;
}
}
void dfs(int u, int tp){
top[u] = tp; if(son[u]) dfs(son[u],tp);
for(int i = fi[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa[u] || t == son[u]) continue; dfs(t,t);
}
}
int lca(int x, int y){
while(top[x] ^ top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
} return dep[x] < dep[y] ? x : y;
}
namespace AC{
cs int N = ::N * 10;
int ch[N][26], ct[N], nd;
int ins(char *S){
int len = strlen(S), now = 0;
for(int i = 0; i < len; i++){
int c = S[i]-'a'; if(!ch[now][c]) ch[now][c] = ++nd;
now = ch[now][c];
} return now;
}
void putcol(string S, int v){
int len = S.length(), now = 0;
for(int i = 0; i < len; i++){
now = ch[now][S[i]-'a']; if(!now) return;
ct[now] += v;
}
}
}
void work(int u, int fa){
for(int i = 0; i < qry[u].size(); i++){
query now = qry[u][i];
ans[now.c] += now.op * AC::ct[now.u];
}
for(int i = fi[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa) continue;
AC::putcol(w[i], 1);
work(t, u);
AC::putcol(w[i], -1);
}
}
int main(){
freopen("strings.in","r",stdin);
freopen("strings.out","w",stdout);
n = read(); char s[10];
for(int i = 1, x, y; i < n; i++){
x = read(), y = read(); scanf("%s",s);
string S = s; add(x,y,S); add(y,x,S);
} pre_dfs(1, 0); dfs(1, 1);
q = read();
for(int i = 1; i <= q; i++){
int u = read(), v = read(); scanf("%s",s);
int nx = AC::ins(s);
qry[u].pb(query(nx, 1, i));
qry[v].pb(query(nx, 1, i));
qry[lca(u, v)].pb(query(nx, -2, i));
} work(1, 0);
for(int i = 1; i <= q; i++) cout << ans[i] << '\n';
return 0;
}