题目链接

思路

对于每一种颜色都建立一个动态开点线段树。然后每次查询的时候就去这个颜色的线段树上查询就行了。修改之后不要忘记交换颜色。

这个题目数据有点强。抄了个比较快的读入优化才卡过去。

代码

/*
* @Author: wxyww
* @Date:   2018-12-13 08:59:51
* @Last Modified time: 2018-12-13 09:56:16
*/
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 600000;
#include <sys/mman.h>
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#define Finline __inline__ __attribute__ ((always_inline))
struct io{
    char *s;
    io():s((char*)mmap(0, 1<<26, PROT_READ, MAP_PRIVATE, fileno(stdin), 0)) {}
    inline operator int()
    {
        register int x=0;
        for(;*s<48;++s);
        for(;*s>47;)x=x*10+*s++-48;
        return x;
    }
}io;
int TR[N * 20],a[N],ls[N * 20],rs[N * 20];
int tot,root[N];
inline void update(int &cur,int l,int r,int pos,int c) {
    if(!cur) cur = ++tot;
    if(l == r) {
        TR[cur] += c;
        return;
    }
    TR[cur] += c;
    int mid = (l + r) >> 1;
    if(pos <= mid) update(ls[cur],l,mid,pos,c);
    else update(rs[cur],mid + 1,r,pos,c);
}
inline int query(int cur,int l,int r,int L,int R) {
    if(L <= l && R >= r) return TR[cur];
    int mid = (l + r) >> 1,ans = 0;
    if(L <= mid) ans += query(ls[cur],l,mid,L,R);
    if(R > mid) ans += query(rs[cur],mid + 1,r,L,R);
    return ans;
}
int main() {
    int n = io,m = io;
    for(int i = 1;i <= n;++i) {
        a[i] = io;
        update(root[a[i]],1,n,i,1);
    }
    while(m--) {
        int opt = io;
        if(opt == 1) {
            int l = io,r = io,c = io;
            printf("%d\\n",query(root[c],1,n,l,r));
        }
        else {
            int x = io;
            update(root[a[x]],1,n,x,-1);
            update(root[a[x]],1,n,x + 1,1);
            update(root[a[x + 1]],1,n,x + 1,-1);
            update(root[a[x + 1]],1,n,x,1);
            swap(a[x],a[x + 1]);
        }
    }
    return 0;
}
收藏 打印