刷漆升级(分块)

来源:互联网 发布:一人能做好淘宝网店吗 编辑:程序博客网 时间:2024/04/26 19:07

刷漆升级

思路

本来打的线段树
敲了半天,大佬说这题线段树被卡95分。。。
不过这题用分块做确实方便一点,而且跑的还快

颜色的数据范围有2^31,直接开数组会炸掉
而且要实现快速查询,更改,删除
显然用map来维护比较好
区间更改,所以要延迟更新

题解

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<map>using namespace std;#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;++i)#define DOR(i,a,b) for(int i=(a),i##_end_=(b);i>=i##_end_;--i)#define INF 0x3f3f3f3f#define M 100005#define N 350inline void chkmx(int &a,int b){if(a<b)a=b;}inline void chkmi(int &a,int b){if(a>b)a=b;}inline int MAX(int a,int b){return a>b?a:b;}inline int MIN(int a,int b){return a<b?a:b;}struct node {    int L,R,f;    map<int,int> mp;    node(){mp.clear();f=-1;}} blk[N];int A[M];int n,m,k,l;void build(){    l=(int)sqrt(n);    FOR(i,0,n-1) blk[i/l].mp[A[i]]++;    FOR(i,0,(n-1)/l) blk[i].L=i*l,blk[i].R=i*l+l-1;    blk[(n-1)/l].R=n-1;}void down(int s){    if(blk[s].f==-1) return ;    FOR(i,blk[s].L,blk[s].R) A[i]=blk[s].f;    blk[s].f=-1;}void Fill(int L,int R,int s,int a){    FOR(i,L,R) A[i]=a;    blk[s].mp.clear();    FOR(i,blk[s].L,blk[s].R) blk[s].mp[A[i]]++;}void update(int L,int R,int a){    int s1=L/l,s2=R/l;    if(s1==s2){        down(s1);        Fill(L,R,s1,a);        return ;    }    down(s1);    Fill(L,blk[s1].R,s1,a);    FOR(i,s1+1,s2-1){        blk[i].f=a;        blk[i].mp.clear();        blk[i].mp[a]=l;    }    down(s2);    Fill(blk[s2].L,R,s2,a);}int query(int L,int R,int a){    int s1=L/l,s2=R/l,tmp=0;    if(s1==s2){        down(s1);         FOR(i,L,R) if(A[i]==a) tmp++;        return tmp;    }    down(s1);    FOR(i,L,blk[s1].R)if(A[i]==a) tmp++;    FOR(i,s1+1,s2-1) tmp+=blk[i].mp[a];    down(s2);    FOR(i,blk[s2].L,R)if(A[i]==a) tmp++;    return tmp;}int main() {    cin>>n>>m;    FOR(i,0,n-1) scanf("%d",&A[i]);    build();    while(m--){        int op,L,R,a;        scanf("%d%d%d%d",&op,&L,&R,&a);        if(op==1) update(L,R,a);        else printf("%d\n",query(L,R,a));    }    return 0;}