[模拟赛] 补番计划

Description

小X,作为一只死宅,又攒了好多新番要补。

然而由于他的大多数时间都被用来学OI(推galgame)了,他补番的方案要精打细算。

于是他把所有要补的番排成一个长度为\(n\)序列,利用这个序列优化他的方案。

具体说,序列中的每部番都有一个特征值\(a_i\)

而由于他每天的心情不同,想看番的期望值\(k\)也不同。

每次,他会选择一个区间\([l,r]\),然后把这个区间内特征值\(a_i\)和他的期望值\(k\)相同的番都补一集。

他想知道这次操作要补多少集番,来预估自己晚上有没有时间睡觉。

当然,由于某些特殊的影响,小X会放弃某个番剧\(i\),并将其替换,于是他会把\(a_i\)的值修改为\(x\)

对于小X的每次询问操作,你都需要输出他补多少集番。

Input

第一行两个整数\(n,m\),表示序列长度和操作次数。

第二行\(n\)个整数\(a_1\)-\(a_n\),表示初始序列。

接下来\(m\)行,每行一个整数\(o\),表示操作类型。

如果\(o = 1\),表示这是一个询问操作,接下来三个整数\(l,r,k\),表示小X补番的区间和期望的特征值\(k\)

如果\(o = 2\),表示这是一个修改操作,接下来两个整数\(p,x\),表示小X将序列第\(p\)项替换为特征值为\(x\)的番剧。

强制在线,\(l\)\(r\)\(p\)都要加上上一次的答案\(lastans\)并对\(n\)取模并\(+1\),如果取模后\(l>r\),请自行交换\(l,r\)

Output

对于每个询问操作,输出一个整数\(ans_i\),表示小X补番的数量。

Hint

对于\(100\%\)的数据,\(n,m\leq 7\times 10^5\)

所有特征值\(a_i\)均不超过\(MAX_{}INT\)且非负。

时间限制\(3s\),空间限制\(40MB\)

Source

Cmd2001

Solution

乍一看是 \(7e5\) 的强制在线数颜色,但是询问的是特定值的个数。

所以考虑对于每个特征值维护一棵平衡树。

对于每个特征值我们用一棵 \(fhq_{}Treap\) 维护有哪些位置有这个特征值。

\(1\) 操作,可以把这棵树上 \(split\)\([l,r]\) 这段区间,然后求根节点的 \(size\) 就好。

\(2\) 操作,先在这个位置原来的特征值中的 \(Treap\) 中删掉这个位置,然后将新的特征值的 \(Treap\) 里插入当前位置即可。

水题水题~
那你还打40分暴力

Code

#include<map>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#define min(A,B) (A)<(B)?(A):(B)
#define max(A,B) (A)>(B)?(A):(B)
#define N 700005+1005
#define inf 0x3f3f3f3f

int n,m;
int a[N];
int cur,cnt;
int del_cur;
int root[N];
int delpool[1005];
int prio[N],val[N];
int sze[N],ch[N][2];
std::map<int,int> mp;

int newnode(){
    if(del_cur) return delpool[del_cur--];
    return ++cur;
}

void read(int &x){
    x=0; char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}

void write(int x){
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

void pushup(int now){
    sze[now]=sze[ch[now][0]]+sze[ch[now][1]]+1;
}

void split(int now,int k,int &x,int &y){
    if(!now) x=y=0;
    else{
        if(val[now]<k){
            x=now;
            split(ch[now][1],k,ch[now][1],y);
        }
        else{
            y=now;
            split(ch[now][0],k,x,ch[now][0]);
        }
        pushup(now);
    }
}

int merge(int x,int y){
    if(!x or !y) return x+y;
    if(prio[x]<prio[y]){
        ch[x][1]=merge(ch[x][1],y);
        pushup(x);
        return x;
    }
    ch[y][0]=merge(x,ch[y][0]);
    pushup(y);
    return y;
}

int new_node(int b){
    int now=newnode();
    sze[now]=1;
    val[now]=b;
    prio[now]=rand();
    ch[now][0]=ch[now][1]=0;
    return now;
}

void insert(int c,int b){
    int x,y;
    split(root[c],b,x,y);
    root[c]=merge(x,merge(new_node(b),y));
}

int query(int e,int b,int c){
    int x,y,z,d;
    split(root[c],e,x,y);
    split(y,b+1,y,z);
    int k=sze[y];
    root[c]=merge(x,merge(y,z));
    return k;
}

void remove(int c,int b){
    int x,y,z;
    split(root[c],b,x,y);
    split(y,b+1,y,z);
    root[c]=merge(x,z);
    delpool[++del_cur]=y;
}

signed main(){
    srand(2002+01+22);
    read(n),read(m);
    for(int x,i=1;i<=n;i++){
        read(x); a[i]=x;
        if(!mp[x]) mp[x]=++cnt;
        insert(mp[x],i);
    }
    int last=0;
    while(m--){
        int o,l,r,k;
        read(o);
        if(o==1){
            read(l),read(r),read(k);
            l=(l+last)%n+1;
            r=(r+last)%n+1;
            if(l>r) l^=r^=l^=r;
            last=query(l,r,mp[k]);
            write(last); putchar('\n');
        }
        else{
            read(l),read(r);
            l=(l+last)%n+1;
            if(!mp[r]) mp[r]=++cnt;
            remove(mp[a[l]],l);
            a[l]=r;
            insert(mp[r],l);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/YoungNeal/p/9074627.html
今日推荐