一道题20

$n \leq 100000$的字符串,多次问一个区间有多少位置不同的回文串。

先插空做一次manacher,得到每个字符往左右延伸的长度$f$数组。如ACAA变*A*C*A*A*,那么所有*的$f_k$实际对应的回文串数是$\frac{f_k}{2}$(一定整除),否则是$\frac{f_k+1}{2}$(一定整除)。算答案的时候把后者的+1提出来,假设询问原串的区间$l,r$,那就是询问新串的$L=2l-1,R=2r+1$,只要输出$\frac{1}{2}(r-l+1+\sum_{k=L}^{R}min{f_k,k-L,R-k})$即可。

$\sum$那坨东西从$\frac{L+R}{2}$处劈开得到两边,左边是$min{f_k,k-L}$,可以分类把$min$去掉,即$min{f_k,k-L}=f_k,k-f_k \geq L$,$min{f_k,k-L}=k-L,k-f_k<L$,变成了一个二维数点问题,为了方便直接主席树搞定;右边同理。

这个式子很好想到,稍加分析就可以求得,因此见到陌生的式子不要虚,按套路一步步求就好了。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<time.h>
 5 //#include<math.h>
 6 //#include<set>
 7 //#include<queue>
 8 //#include<bitset>
 9 //#include<vector>
10 #include<algorithm>
11 #include<stdlib.h>
12 using namespace std;
13 
14 #define LL long long
15 LL qread()
16 {
17     char c; LL s=0; int f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
18     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
19 }
20 
21 //Pay attention to '-' , LL and double of qread!!!!
22 
23 int n,m;
24 #define maxn 260011
25 char s[maxn]; int f[maxn];
26 int r1[maxn],r2[maxn];
27 struct SMT
28 {
29     struct Node{int ls,rs; LL f,k,c;}a[maxn*20];
30     int size,n;
31     void clear(int N) {n=N; size=0;}
32     LL sf,sk,sc; int v;
33     void in(int &x,int y,int L,int R,int p,int f,int k)
34     {
35         x=++size; a[x].f=a[y].f+f; a[x].k=a[y].k+k; a[x].c=a[y].c+1;
36         if (L==R) return;
37         int mid=(L+R)>>1;
38         if (p<=mid) in(a[x].ls,a[y].ls,L,mid,p,f,k),a[x].rs=a[y].rs;
39         else in(a[x].rs,a[y].rs,mid+1,R,p,f,k),a[x].ls=a[y].ls;
40     }
41     void in(int &x,int y,int p,int f,int k) {in(x,y,1,n,p,f,k);}
42     void Query(int x,int L,int R,int ql,int qr)
43     {
44         if (ql<=L && R<=qr) {sf+=a[x].f*v; sk+=a[x].k*v; sc+=a[x].c*v; return;}
45         int mid=(L+R)>>1;
46         if (ql<=mid) Query(a[x].ls,L,mid,ql,qr);
47         if (qr>mid) Query(a[x].rs,mid+1,R,ql,qr);
48     }
49     void query(int x,int y,int l,int r) {sf=sk=sc=0; v=1; Query(y,1,n,l,r); v=-1; Query(x,1,n,l,r);}
50 }
51 t1,t2;
52 
53 struct Lisa {int id,v; bool operator < (const Lisa &b) const {return v<b.v;} }lisa1[maxn],lisa2[maxn];
54 int id1[maxn],id2[maxn];
55 
56 int main()
57 {
58     n=qread(); m=qread(); scanf("%s",s+1);
59     for (int i=n;i;i--) s[i<<1]=s[i]; n=(n<<1)^1;
60     for (int i=1;i<=n;i+=2) s[i]='$';
61     
62     for (int i=1,id=0;i<=n;i++)
63     {
64         if (f[id]+id>=i) f[i]=min(f[id]+id-i,f[id+id-i]);
65         while (i+f[i]+1<=n && i-f[i]-1>0 && s[i+f[i]+1]==s[i-f[i]-1]) f[i]++;
66         if (i+f[i]>f[id]+id) id=i;
67     }
68     
69     for (int i=1;i<=n;i++) lisa1[i]=(Lisa){i,i-f[i]},lisa2[i]=(Lisa){i,i+f[i]};
70     sort(lisa1+1,lisa1+1+n); sort(lisa2+1,lisa2+1+n);
71     for (int i=1;i<=n;i++) id1[lisa1[i].id]=i,id2[lisa2[i].id]=i;
72     t1.clear(n); t2.clear(n);
73     for (int i=1;i<=n;i++)
74     t1.in(r1[i],r1[i-1],id1[i],f[i],i),t2.in(r2[i],r2[i-1],id2[i],f[i],i);
75     
76     int l,r;
77     while (m--)
78     {
79         l=qread(); r=qread();
80         LL ans=r-l+1;
81         l=2*l-1; r=2*r+1;
82         int mid=(l+r)>>1;
83         int p=upper_bound(lisa1+1,lisa1+1+n,(Lisa){0,l})-lisa1-1;
84         t1.query(r1[l-1],r1[mid],1,p);
85         ans+=t1.sk-t1.sc*l;
86         t1.query(r1[l-1],r1[mid],p+1,n);
87         ans+=t1.sf;
88         p=upper_bound(lisa2+1,lisa2+1+n,(Lisa){0,r})-lisa2-1;
89         t2.query(r2[mid],r2[r],1,p);
90         ans+=t2.sf;
91         t2.query(r2[mid],r2[r],p+1,n);
92         ans+=t2.sc*r-t2.sk;
93         printf("%lld\n",ans/2);
94     }
95     return 0;
96 }
View Code

 

posted @ 2018-07-12 15:52  Blue233333  阅读(226)  评论(1编辑  收藏  举报