1. 程式人生 > >bzoj2754 [SCOI2012]喵星球上的點名 (後綴數組+樹狀數組)

bzoj2754 [SCOI2012]喵星球上的點名 (後綴數組+樹狀數組)

rmq 正整數 方法 一個 留學生 sci oid 字符 update

2754: [SCOI2012]喵星球上的點名

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 2745 Solved: 1190
[Submit][Status][Discuss]

Description

a180285幸運地被選做了地球到喵星球的留學生。他發現喵星人在上課前的點名現象非常有趣。 假設課堂上有N個喵星人,每個喵星人的名字由姓和名構成。喵星球上的老師會選擇M個串來點名,每次讀出一個串的時候,如果這個串是一個喵星人的姓或名的子串,那麽這個喵星人就必須答到。 然而,由於喵星人的字碼過於古怪,以至於不能用ASCII碼來表示。為了方便描述,a180285決定用數串來表示喵星人的名字。

現在你能幫助a180285統計每次點名的時候有多少喵星人答到,以及M次點名結束後每個喵星人答到多少次嗎?

Input

現在定義喵星球上的字符串給定方法:
先給出一個正整數L,表示字符串的長度,接下來L個整數表示字符串的每個字符。
輸入的第一行是兩個整數N和M。
接下來有N行,每行包含第i 個喵星人的姓和名兩個串。姓和名都是標準的喵星球上的字符串。
接下來有M行,每行包含一個喵星球上的字符串,表示老師點名的串。

Output

對於每個老師點名的串輸出有多少個喵星人應該答到。
然後在最後一行輸出每個喵星人被點到多少次。


把姓名串和詢問串連在一起求\(SA\),以下為\(rk\)意義下;
然後對於每一個詢問串二分求出\(LCP\)

等於它長度的區間,及詢問串出現位置;
這樣的話第一問就是求每個區間內不同的數的個數,即\(HH\)的項鏈,莫隊/樹狀數組;
第二問一個區間中屬於同一個串的多個後綴會被重復計算,所以把相鄰的重復後綴的貢獻作差;
對於每個詢問\([l,r]\),在\(l\)處將\(w\)區間加\(1\)\(r+1\)處區間減\(1\),則後綴\(i\)的貢獻為\(w[i]-w[las[num[i]]]\)
\(las[num[i]]\)為上一個與\(i\)母串相同的後綴,樹狀數組即可;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string> #include<cstdio> #include<vector> #include<cmath> #include<queue> #include<map> #include<set> #define N 600039 #define mod 20070831 #define inf 0x3f3f3f3f #define ll long long using namespace std; struct question { int sd,l,r,ans; }ask[N/6]; int neko,wa,fir[N/3],len[N/3],bel[N],bit[N],ans[N]; int n,m,num[N],SA[N],rk[N],Height[N],las[N],buc[N],pw[20],st[N][20]; bool cmp_hh(question i,question j) {return i.r<j.r;} bool cmp_sd(question i,question j) {return i.sd<j.sd;} void get_string(int stp) { fir[stp]=n+1; scanf("%d",&len[stp]); for(int a=1;a<=len[stp];a++) { scanf("%d",&num[++n]); num[n]++,bel[n]=stp; } num[++n]=10001+stp; } bool judge(int i,int j,int k) { return las[i]==las[j] && las[i+k]==las[j+k]; } void radix_sort() { for(int a=1;a<=m;a++) buc[a]=0; for(int a=1;a<=n;a++) buc[rk[las[a]]]++; for(int a=1;a<=m;a++) buc[a]+=buc[a-1]; for(int a=n;a>=1;a--) SA[buc[rk[las[a]]]--]=las[a]; } void get_SA() { for(int a=1;a<=n;a++) rk[a]=num[a],las[a]=a; m=N-39,radix_sort(); for(int a=1,b=0;m<n || a==1;a<<=1,b=0) { for(int c=n-a+1;c<=n;c++) las[++b]=c; for(int c=1;c<=n;c++) if(SA[c]>a) las[++b]=SA[c]-a; radix_sort(),m=0; for(int c=1;c<=n;c++) las[c]=rk[c]; for(int c=1;c<=n;c++) rk[SA[c]]=(judge(SA[c-1],SA[c],a) ? m : ++m); } for(int a=1,b=0;a<=n;a++,b=max(0,b-1)) { while(num[a+b]==num[SA[rk[a]-1]+b]) b++; Height[rk[a]]=b; } } void get_st() { pw[0]=1; for(int a=1;pw[a-1]<=n;a++) pw[a]=pw[a-1]<<1; for(int a=1;a<=n;a++) st[a][0]=Height[a]; for(int a=1;pw[a]<=n;a++) { for(int b=1;b<=n;b++) { st[b][a]=min(st[b][a-1],st[b+pw[a-1]][a-1]); } } } int RMQ(int l,int r) { int stp=log((double)r-l+1)/log(2.0); return min(st[l][stp],st[r-pw[stp]+1][stp]); } int search_mae(int stp) { int l=1,r=rk[fir[stp]]-1,mid,res=rk[fir[stp]]; while(l<=r) { mid=l+r>>1; if(RMQ(mid+1,rk[fir[stp]])<len[stp]) l=mid+1; else r=mid-1,res=mid; } return res; } int search_ato(int stp) { int l=rk[fir[stp]]+1,r=n,mid,res=rk[fir[stp]]; while(l<=r) { mid=l+r>>1; if(RMQ(rk[fir[stp]]+1,mid)<len[stp]) r=mid-1; else l=mid+1,res=mid; } return res; } void update(int p,int v) { if(!p) return; while(p<=n) bit[p]+=v,p+=(-p&p); } int query(int p) { int res=0; while(p) res+=bit[p],p-=(-p&p); return res; } int main() { scanf("%d%d",&neko,&wa); for(int a=1,b;a<=neko;a++) { get_string(2*a-1); get_string(2*a); } for(int a=1,b;a<=wa;a++) { get_string(2*neko+a); } get_SA(),get_st(); for(int a=1;a<=wa;a++) { ask[a].sd=a; ask[a].l=search_mae(2*neko+a); ask[a].r=search_ato(2*neko+a); } sort(ask+1,ask+wa+1,cmp_hh); for(int a=0;a<=neko;a++) las[a]=0; for(int a=1,b=1;a<=wa;a++) { while(b<=ask[a].r) { if(bel[SA[b]]<=2*neko) { update(las[bel[SA[b]]+1>>1],-1); las[bel[SA[b]]+1>>1]=b; update(b,1); } b++; } ask[a].ans=query(ask[a].r)-query(ask[a].l-1); } for(int a=0;a<=neko;a++) las[a]=0; for(int a=1;a<=n;a++) bit[a]=0; for(int a=1;a<=wa;a++) update(ask[a].l,1); for(int a=1,b=1;a<=n;a++) { while(b<=wa && ask[b].r<a) { update(ask[b].l,-1); b++; } if(bel[SA[a]]<=2*neko) { ans[bel[SA[a]]+1>>1]+=query(a)-query(las[bel[SA[a]]+1>>1]); las[bel[SA[a]]+1>>1]=a; } } sort(ask+1,ask+wa+1,cmp_sd); for(int a=1;a<=wa;a++) printf("%d\n",ask[a].ans); for(int a=1;a<=neko;a++) { printf("%d",ans[a]); if(a<neko) printf(" "); } return 0; }

bzoj2754 [SCOI2012]喵星球上的點名 (後綴數組+樹狀數組)