[权值线段树] Jzoj P4417 神奇的字符串

Description
 
Input
Output
 
Sample Input
9 5 6 4 3
101
11
Query 0
Query 1
Query 2
Query 3
Query 4
Query 5
Query 6
Query 7
Query 8
Change 1
Query 3
Sample Output
0
3
0
2
2
0
3
0
3
1
 
Data Constraint

 

题解

  • 显然,直接用字符串匹配是不可做的。
  • 考虑把(A*i+B)%N相同的分成一类,它们其实都是一段连续的区间
  • 它们对应的开头也是有序的c[j-i]=c[j]-a*i,所以开头也是有序的
  • 那么就形成了很多个区间,这个点被多少个区间所覆盖也就是说他和s串有多少个字符是相同的
  • 答案就是用总数-被区间覆盖的个数

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 const int M=100010;
 6 int n,a,b,p,m,c[M],tot=1,Q,x;
 7 char ch[10];
 8 struct node{ int l,r,v,lazy; }tree[10000005];
 9 struct edge{ int l,r; };
10 edge work(int x,int y)
11 {
12     int l,r;
13     if (y==0) l=p,r=n-1; else l=0,r=p-1;
14     l=((l-a*x)%n+n)%n,r=((r-a*x)%n+n)%n;
15     return (edge){l,r};
16 }
17 void Lazy(int x)
18 {
19     tree[tree[x].l].lazy+=tree[x].lazy,tree[tree[x].l].v+=tree[x].lazy;
20     tree[tree[x].r].lazy+=tree[x].lazy,tree[tree[x].r].v+=tree[x].lazy;
21     tree[x].lazy=0;
22 }
23 void change(int d,int l,int r,int L,int R,int k)
24 {
25     if (l==L&&r==R) { tree[d].v+=k,tree[d].lazy+=k; return; }
26     int mid=l+r>>1;
27     if (!tree[d].l) tree[d].l=++tot; if (!tree[d].r) tree[d].r=++tot;
28     Lazy(d);
29     if (R<=mid) change(tree[d].l,l,mid,L,R,k); else if (L>mid) change(tree[d].r,mid+1,r,L,R,k);
30     else change(tree[d].l,l,mid,L,mid,k),change(tree[d].r,mid+1,r,mid+1,R,k);
31 }
32 int Query(int d,int l,int r,int k)
33 {
34     if (l==r) return tree[d].v;
35     int mid=l+r>>1;
36     if (!tree[d].l) tree[d].l=++tot; if (!tree[d].r) tree[d].r=++tot;
37     Lazy(d);
38     return (k<=mid)?Query(tree[d].l,l,mid,k):Query(tree[d].r,mid+1,r,k);
39 }
40 int main()
41 {
42     scanf("%d%d%d%d%d",&n,&a,&b,&p,&m);
43     for (int i=1;i<=m;i++)
44     {
45         char ch=' '; while (ch!='0'&&ch!='1') ch=getchar();
46         c[i]=ch-48; edge e=work(i-1,c[i]); 
47         if (e.l<=e.r) change(1,0,n-1,e.l,e.r,1); else change(1,0,n-1,0,e.r,1),change(1,0,n-1,e.l,n-1,1);
48     }
49     scanf("%d\n",&Q);
50     while (Q--)
51     {
52         scanf("%s%d\n",ch,&x);
53         if (ch[0]=='Q') printf("%d\n",Query(1,0,n-1,(x*a+b)%n));
54         else 
55         {
56             x++; edge e=work(x-1,c[x]);
57             if (e.l<=e.r) change(1,0,n-1,e.l,e.r,-1); else change(1,0,n-1,0,e.r,-1),change(1,0,n-1,e.l,n-1,-1);
58             c[x]=(c[x]+1)%2,e=work(x-1,c[x]);
59             if (e.l<=e.r) change(1,0,n-1,e.l,e.r,1); else change(1,0,n-1,0,e.r,1),change(1,0,n-1,e.l,n-1,1);
60         }
61     }
62 }

 

转载于:https://www.cnblogs.com/Comfortable/p/10290400.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值