jzoj4417 【HNOI2016模拟4.1】神奇的字符串 (映射,权值线段树)

来源:互联网 发布:使命召唤mac版下载 编辑:程序博客网 时间:2024/06/15 17:07

题意

这里写图片描述

这里写图片描述

分析

一开始看到的时候一脸黑人问号
注意到条件(n,a)=1,这意味着(ai+b)%n(aj+b)%n.
转换一下问题,我们用数据结构统计s[i]对每一个开头c[i]的贡献。

因为题目询问是不同的个数,所以s[i]=1如果有贡献,那么它一定对应c[j]=0j
于是我们按照f(i)=(Ai+B)%N,将ci排好序,称为b

s[i]=1有贡献的c[j]就是b[0,p1]映射的这些。这些c[i]在b上被排到了一起,但在c中并不是靠在一起的。

因为c[j]并不是对应的开头,我们需要将贡献累加到开头c[st]上。
c[st]映射到b上之后是否还靠在一起呢?
st=j-i (从0开始标号)

(f(ji)+Ai)%n=f(j) ,由此可以看出,所有的合法开头在b中所对应的位置f(st)都是连续的。
f(st)是在模意义下的,所以负数区间也被允许。 同样地,大于n-1的区间也被允许。

这一题的关键之处在于把握c[i]在b中的映射位置f(i)与c[i-j]在b中的映射位置f(ij)的关系,两者在c中差j,在b中差aj
这样我们就把所有任意s[i]需要累加贡献的位置映射到一段区间内,使用动态开点+权值线段树保存修改即可。

Code

#include <iostream>#include <cstdio>#include <bitset>#define N 101000#define SZ 12000000#define f(i) (((i)*a+b)%n)#define tag(x,y) ((x)!=0?lazy[x]+=(y):0)using namespace std;int s[N];int n,a,b,p,m,q;int lc[SZ],rc[SZ],tot,lazy[SZ],root;void down(int x) {    if (lazy[x]) tag(lc[x],lazy[x]),tag(rc[x],lazy[x]),lazy[x]=0;}void query(int x,int l,int r,int tg,int &ans) {    if (x==0) return;    if (l>tg || r<tg) return;    if (l==r) {        ans=lazy[x]; return;    }    if (!lc[x]) lc[x]=++tot;    if (!rc[x]) rc[x]=++tot;    down(x);    query(lc[x],l,l+r>>1,tg,ans);    query(rc[x],(l+r>>1)+1,r,tg,ans);}void change(int &x,int l,int r,int tl,int tr,int v) {    if (tr<l || tl>r) return;    if (x==0) x=++tot;    if (tl<=l && r<=tr) {tag(x,v); return;}    change(lc[x],l,l+r>>1,tl,tr,v);    change(rc[x],(l+r>>1)+1,r,tl,tr,v);}void add(int x,int y,int v) {    x=(x%n+n)%n,y=(y%n+n)%n;    if (x<y) change(root,0,n-1,x,y,v);    else {        change(root,0,n-1,0,y,v);        change(root,0,n-1,x,n-1,v);    }}int main() {    freopen("3.in","r",stdin); freopen("3.out","w",stdout);    cin>>n>>a>>b>>p>>m; scanf("\n");    char cc;    for (int i=0; i<m; i++) {        scanf("%c",&cc),s[i]=cc-'0';        if (s[i]==1) add(0-a*i,p-1-a*i,1);        else add(p-a*i,n-1-a*i,1);    }    cin>>q;int cnt=0;    for (int i=1; i<=q; i++) {        scanf("\n"); cc=getchar();        if (cc=='Q')  {            int st,ans=0; scanf("uery %d",&st);            query(1,0,n-1,f(st),ans);            printf("%d\n",ans);        } else {            int t; scanf("hange %d",&t);            if (s[t]==0) {                add(p-a*t,n-1-a*t,-1);                add(0-a*t,p-a*t-1,1);            } else {                add(p-a*t,n-1-a*t,1);                add(0-a*t,p-a*t-1,-1);            }            s[t]^=1;        }    }}