题目描述
a180285 幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。
假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。
然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示。为了方便描述,a180285 决定用数串来表示喵星人的名字。
现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结束后每个喵星人答到多少次吗?
输入输出格式
输入格式:
现在定义喵星球上的字符串给定方法:
先给出一个正整数 L ,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数 N 和 M。
接下来有 N 行, 每行包含第 i 个喵星人的姓和名两个串。 姓和名都是标准的喵星球上的字符串。
接下来有 M 行,每行包含一个喵星球上的字符串,表示老师点名的串。
输出格式:
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
~~~~~~~~~~~~~~~~~~
某谷恶意加强数据。
首先吐槽卡trie图。字符集太大了,trie图会T得很厉害,建个图就超时了。
别人用map,然而我不喜欢迭代器,就用了treap维护儿子。
代码:
#include<ctime> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define N 200050 #define M 200050 inline int rd() { int f=1,c=0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=(c<<3)+(c<<1)+ch-'0';ch=getchar();} return f*c; } int n,m,tot; int ls[M<<1],rs[M<<1],rnd[M<<1],w[M<<1]; struct Treap { int rt; void lturn(int &x) { int y = rs[x]; rs[x]=ls[y],ls[y]=x; x=y; } void rturn(int &x) { int y = ls[x]; ls[x]=rs[y],rs[y]=x; x=y; } int query(int k,int x) { if(w[k]==x)return k; if(!k)return 0; return query(w[k]<x?rs[k]:ls[k],x); } void insert(int &k,int x) { if(!k) { k=++tot; rnd[k]=rand(); w[k]=x; return ; }else if(w[k]<x) { insert(rs[k],x); if(rnd[rs[k]]<rnd[k])lturn(k); }else { insert(ls[k],x); if(rnd[ls[k]]<rnd[k])rturn(k); } } }; int lin[M],sum; struct nam { int len1,len2; int l1,r1,l2,r2; }q[N]; int hed[M<<1],cntt; struct Trie { Treap ch; // vector<int>vv; int f,ct; }tr[M<<1]; struct EG { int to,nxt; }e[M]; void ae(int f,int t) { e[++cntt].to = t; e[cntt].nxt = hed[f]; hed[f] = cntt; } bool vis1[M],vis2[M]; void init() { for(int i=1;i<=tot;i++) vis1[i]=0; for(int i=1;i<=n;i++) vis2[i]=0; } void acmach() { queue<int>q,c; q.push(0); while(!q.empty()) { int u = q.front(); q.pop(); if(!tr[u].ch.rt)continue; c.push(tr[u].ch.rt); while(!c.empty()) { int v = c.front(); c.pop(); if(ls[v])c.push(ls[v]); if(rs[v])c.push(rs[v]); int to = tr[u].f; while(to&&!tr[to].ch.query(tr[to].ch.rt,w[v]))to=tr[to].f; int hhh=tr[to].ch.query(tr[to].ch.rt,w[v]); if(hhh&&u)to=hhh; tr[v].f = to; q.push(v); } } } int as1[N],as2[M]; int deal(int u) { int ret = 0; while(!vis1[u]) { for(int j=hed[u];j;j=e[j].nxt) { int i = e[j].to; vis2[i]=1; as2[i]++; } ret+=tr[u].ct; vis1[u]=1; u = tr[u].f; } return ret; } int main() { srand(time(NULL)); n=rd(),m=rd(); int u,c,v; for(int i=1;i<=n;i++) { q[i].len1=rd(); q[i].l1 = sum+1,q[i].r1 = sum+q[i].len1; for(int j=q[i].l1;j<=q[i].r1;j++)lin[j]=rd(); sum+=q[i].len1; q[i].len2=rd(); q[i].l2 = sum+1,q[i].r2 = sum+q[i].len2; for(int j=q[i].l2;j<=q[i].r2;j++)lin[j]=rd(); sum+=q[i].len2; } for(int i=1;i<=m;i++) { c=rd(); u=0; for(int j=1;j<=c;j++) { v=rd(); if(!tr[u].ch.query(tr[u].ch.rt,v))tr[u].ch.insert(tr[u].ch.rt,v); u = tr[u].ch.query(tr[u].ch.rt,v); } // tr[u].vv.push_back(i); ae(u,i); tr[u].ct++; } acmach(); vis1[0]=1; for(int i=1;i<=n;i++) { init(); u=0; for(int j=q[i].l1;j<=q[i].r1;j++) { c = lin[j]; while(u&&!tr[u].ch.query(tr[u].ch.rt,c))u=tr[u].f; int hhh = tr[u].ch.query(tr[u].ch.rt,c); if(hhh)u=hhh; as1[i]+=deal(u); } u=0; for(int j=q[i].l2;j<=q[i].r2;j++) { c = lin[j]; while(u&&!tr[u].ch.query(tr[u].ch.rt,c))u=tr[u].f; int hhh = tr[u].ch.query(tr[u].ch.rt,c); if(hhh)u=hhh; as1[i]+=deal(u); } } for(int i=1;i<=m;i++)printf("%d\n",as2[i]); for(int i=1;i<=n;i++)printf("%d ",as1[i]); printf("\n"); return 0; }