题意


分析

自己的想法

可以莫队+平衡树。

对每个颜色维护一颗平衡树,然后移动莫队端点的时候在平衡树中查询。

区间加操作容易实现。

单点修改转化为平衡树的插入删除。

感谢Z前辈的指导。

时间复杂度\(O(n^{\frac{5}{3}} \cdot \log n)\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
template<class T>T read(T&x)
{
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return x=data*w;
}
typedef long long ll;
using namespace std;

const int MAXN=1e5+7,mod=998244353;
int n,m;
int blo,bl[MAXN]; // block,belong
int c[MAXN],pre[MAXN],now[MAXN]; // color,撤销操作3用的链表 

queue<int>pool; // 内存池
int root[MAXN],sz;
struct Treap
{
    int ch[MAXN][2],siz[MAXN];
    int pos[MAXN],pri[MAXN]; // 在原序列中的位置,优先级
    int val[MAXN],sumv[MAXN],addv[MAXN]; // 值,子树的值和,加法标记 

    int newnode(int p,int v) // 新建位置为p,值为v的节点
    {
        int nd;
        if(!pool.empty())
        {
            nd=pool.front();
            pool.pop();
        }
        else
        {
            nd=++sz;
        }
        ch[nd][0]=ch[nd][1]=0,siz[nd]=1;
        pos[nd]=p,pri[nd]=rand()|rand()<<15;
        val[nd]=v,sumv[nd]=v,addv[nd]=0;
        return nd;
    }

    void pushup(int now)
    {
//      cerr<<"pushup "<<now<<endl;
        siz[now]=siz[ch[now][0]]+1+siz[ch[now][1]]; // edit 2
        sumv[now]=((ll)sumv[ch[now][0]]+val[now]+sumv[ch[now][1]])%mod;
    }

    void pushdown(int now)
    {
//      cerr<<"pushdown "<<now<<endl;
        if(addv[now])
        {
            if(ch[now][0]) // 判断非空
            {
                (val[ch[now][0]]+=addv[now])%=mod,
                (sumv[ch[now][0]]+=(ll)siz[ch[now][0]]*addv[now]%mod)%=mod,
                (addv[ch[now][0]]+=addv[now])%=mod;
            }
            if(ch[now][1])
            {
                (val[ch[now][1]]+=addv[now])%=mod,
                (sumv[ch[now][1]]+=(ll)siz[ch[now][1]]*addv[now]%mod)%=mod,
                (addv[ch[now][1]]+=addv[now])%=mod;
            }
            addv[now]=0;
        }
    }

    void split(int&now,int p,int&x,int&y) // 将now所代表的子树位置大于等于p的分到y,其余的分到x
    {
//      cerr<<"spliting "<<now<<" "<<p<<endl;
        if(!now)
        {
            x=y=0;
            return;
        }
        pushdown(now);
        if(pos[now]>=p)
        {
//          cerr<<"right"<<endl;
            y=now;
            split(ch[y][0],p,x,ch[y][0]); // edit 1
            pushup(y);
        }
        else
        {
//          cerr<<"left"<<endl;
            x=now;
            split(ch[x][1],p,ch[x][1],y);
            pushup(x);
        }
    }

    int merge(int x,int y) // 合并x子树和y子树,满足x子树中的每一个节点的位置大于y子树中的每一个节点的位置
    {
//      cerr<<"merging "<<x<<" "<<y<<endl;
        if(!x||!y)
        {
            return x+y;
        }
        int now;
        if(pri[x]<pri[y])
        {
            pushdown(x);
            now=x;
            ch[now][1]=merge(ch[x][1],y);
        }
        else
        {
            pushdown(y);
            now=y;
            ch[now][0]=merge(x,ch[y][0]);
        }
        pushup(now);
        return now;
    }

    void ins(int&now,int p,int v) // 插入
    {
        int x,y;
        split(now,p,x,y);
        now=merge(x,merge(newnode(p,v),y));
    }

    int del(int &now,int p) // 删除,返回被删的子树(其实就是节点)
    {
        int x,y,z;
        split(now,p,x,y);
        split(y,p+1,y,z);
        now=merge(x,z);
        return y;
    }

    void add(int&now,int l,int r,int v) // 区间加
    {
        int x,y,z;
        split(now,l,x,y);
        split(y,r+1,y,z);
        if(y) // edit 3:非空才加
        {
            (val[y]+=v)%=mod,
            (sumv[y]+=(ll)siz[y]*v%mod)%=mod,
            (addv[y]+=v)%=mod;
        }
        now=merge(x,merge(y,z));
    }

    int qsum(int&now,int p) // 子树(其实就是节点)求和
    {
        int x,y,z;
        split(now,p,x,y);
        split(y,p+1,y,z);
        int ans=sumv[y]; // y一定存在
        now=merge(x,merge(y,z));
//      cerr<<"qsum "<<now<<" "<<p<<" ans="<<ans<<endl;
        return ans;
    }

    int qnum(int&now,int l,int r) // 子树中位置在区间[l,r]中的节点的个数
    {
        int x,y,z;
        split(now,l,x,y);
        split(y,r+1,y,z);
        int ans=siz[y];
        now=merge(x,merge(y,z));
//      cerr<<"qnum "<<now<<" "<<l<<" "<<r<<" ans="<<y<<" siz="<<siz[y]<<endl;
        return ans;
    }
}T;

struct Add // 区间加以及单点修改操作
{
    int opt;
    int t,l,r,x,y;
}A[MAXN];
int a;

struct Quiz // 查询操作
{
    int t,id,l,r;

    bool operator<(const Quiz&rhs)const
    {
        return bl[l]^bl[rhs.l]?l<rhs.l:(bl[r]<bl[rhs.r]?r<rhs.r:t<rhs.t);
    }
}Q[MAXN];
int ans[MAXN],q;

int qt,ql,qr,sum;

void addAdd(int rk) // 加上A[rk]
{
//  cerr<<"addAdd "<<rk<<endl;
    if(A[rk].opt==1) // 区间加
    {
        if(ql<=A[rk].r&&A[rk].l<=qr) // 修改区间与莫队区间有交
            (sum+=(ll)T.qnum(root[A[rk].x],max(ql,A[rk].l),min(qr,A[rk].r))*A[rk].y%mod)%=mod;
        T.add(root[A[rk].x],A[rk].l,A[rk].r,A[rk].y);
    }
    else // 单点修改
    {
        int nd=T.del(root[c[A[rk].x]],A[rk].x);
        c[A[rk].x]=A[rk].y;
        T.ins(root[A[rk].y],A[rk].x,T.val[nd]);
        pool.push(nd);
    }
}

void delAdd(int rk) // 减去A[rk]
{
//  cerr<<"delAdd "<<rk<<endl;
    if(A[rk].opt==1)
    {
        if(ql<=A[rk].r&&A[rk].l<=qr)
            (sum+=mod-(ll)T.qnum(root[A[rk].x],max(ql,A[rk].l),min(qr,A[rk].r))*A[rk].y%mod)%=mod;
        T.add(root[A[rk].x],A[rk].l,A[rk].r,mod-A[rk].y);
    }
    else
    {
        int nd=T.del(root[c[A[rk].x]],A[rk].x);
        c[A[rk].x]=pre[rk];
        T.ins(root[pre[rk]],A[rk].x,T.val[nd]);
        pool.push(nd);
    }
}

void addQuiz(int p) // 莫队区间加上点
{
//  cerr<<"addQuiz "<<p<<endl;
    (sum+=T.qsum(root[c[p]],p))%=mod;
}

void delQuiz(int p) // 莫队区间减去点
{
//  cerr<<"delQuiz "<<p<<endl;
    (sum+=mod-T.qsum(root[c[p]],p))%=mod;
}

int main()
{
    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    srand(20030506);
    int n,m;
    read(n),read(m);
    blo=pow(n,2.0/3);
    for(int i=1;i<=n;++i)
    {
        bl[i]=(i-1)/blo+1;
    }
    for(int i=1;i<=n;++i)
    {
        now[i]=read(c[i]);
        T.ins(root[c[i]],i,0);
    }
    for(int i=1;i<=m;++i)
    {
        int opt;
        read(opt);
        if(opt==1)
        {
            A[++a].opt=1,A[a].t=i;
            read(A[a].l),read(A[a].r),read(A[a].x),read(A[a].y);
        }
        else if(opt==2)
        {
            Q[++q].t=i,Q[q].id=q;
            read(Q[q].l),read(Q[q].r);
        }
        else if(opt==3)
        {
            A[++a].opt=3,A[a].t=i;
            read(A[a].x),read(A[a].y);
            pre[a]=now[A[a].x];
            now[A[a].x]=A[a].y;
        }
    }
    A[++a].t=1e9;
    sort(Q+1,Q+q+1);
    qt=0,ql=1,qr=0,sum=0;
    for(int i=1;i<=q;++i)
    {
        while(A[qt+1].t<=Q[i].t)
        {
            addAdd(++qt);
        }
        while(A[qt].t>Q[i].t)
        {
            delAdd(qt--);
        }
        while(qr<Q[i].r)
        {
            addQuiz(++qr);
        }
        while(qr>Q[i].r)
        {
            delQuiz(qr--);
        }
        while(ql>Q[i].l)
        {
            addQuiz(--ql);
        }
        while(ql<Q[i].l)
        {
            delQuiz(ql++);
        }
        ans[Q[i].id]=sum;
    }
    for(int i=1;i<=q;++i)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}
/*
10 10
1 9 9 2 9 4 1 2 6 9
3 10 10
2 7 9
1 8 9 2 8
1 2 2 3 7
2 3 6
3 8 8
1 2 4 3 1
1 2 10 1 9
2 7 10
2 1 10
*/

W学霸的做法

直接分块,对每个颜色维护。

代码清晰易懂,并且跑得飞快。

时间复杂度\(O(n \sqrt{n})\)

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#include<cassert>
#define rg register
#define il inline
#define co const
#pragma GCC optimize ("O0")
using namespace std;
template<class T> il T read()
{
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return data*w;
}
template<class T> il T read(T&x)
{
    return x=read<T>();
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=1e5+7,mod=998244353;
int n,m,len;
int bl[MAXN],c[MAXN],a[MAXN];
int cnt[350][MAXN];
int laz[350][MAXN];
int ans[350];

int mul(int x,int y)
{
    return (ll)x*y%mod;
}

int add(int x,int y)
{
    return (x+y)%mod;
}

int pul(int x,int y)
{
    return (x+mod-y)%mod;
}

void change(int l,int r,int x,int y)
{
    if(bl[l]!=bl[r])
    {
        for(int i=bl[l]+1;i<bl[r];++i)
        {
            laz[i][x]=add(laz[i][x],y);
            ans[i]=add(ans[i],mul(cnt[i][x],y));
        }
        for(int i=l;i<=bl[l]*len;++i)
            if(c[i]==x)
            {
                ans[bl[i]]=add(ans[bl[i]],y);
                a[i]=add(a[i],y);
            }
        for(int i=(bl[r]-1)*len+1;i<=r;++i)
            if(c[i]==x)
            {
                ans[bl[i]]=add(ans[bl[i]],y);
                a[i]=add(a[i],y);
            }
    }
    else
    {
        for(int i=l;i<=r;++i)
            if(c[i]==x)
            {
                ans[bl[i]]=add(ans[bl[i]],y);
                a[i]=add(a[i],y);
            }
    }
}

int query(int l,int r)
{
    int res=0;
    if(bl[l]!=bl[r])
    {
        for(int i=bl[l]+1;i<bl[r];++i)
        {
            res=add(res,ans[i]);
        }
        for(int i=l;i<=bl[l]*len;++i)
        {
            res=add(res,add(a[i],laz[bl[i]][c[i]]));
        }
        for(int i=(bl[r]-1)*len+1;i<=r;++i)
        {
            res=add(res,add(a[i],laz[bl[i]][c[i]]));
        }
    }
    else
    {
        for(int i=l;i<=r;++i)
        {
            res=add(res,add(a[i],laz[bl[i]][c[i]]));
        }
    }
    return res;
}

int main()
{
  freopen("color.in","r",stdin);
  freopen("color.out","w",stdout);
    read(n);read(m);
    len=sqrt(n);
    for(int i=1;i<=n;++i)
    {
        bl[i]=(i-1)/len+1;
        read(c[i]);
        ++cnt[bl[i]][c[i]];
    }
    int opt,l,r,x,y;
    for(int i=1;i<=m;++i)
    {
        read(opt);
        if(opt==1)
        {
            read(l);read(r);read(x);read(y);
            change(l,r,x,y);
        }
        else if(opt==2)
        {
            read(l);read(r);
            printf("%d\n",query(l,r));
        }
        else
        {
            read(x);read(y);
            if(c[x]==y)
                continue;
            --cnt[bl[x]][c[x]];
            a[x]=add(a[x],laz[bl[x]][c[x]]);
            if(!cnt[bl[x]][c[x]])
                laz[bl[x]][c[x]]=0;
            c[x]=y;
            a[x]=pul(a[x],laz[bl[x]][c[x]]);
            ++cnt[bl[x]][c[x]];
        }
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

标解

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int, int> PII;
#define fi first
#define se second
#define MP make_pair

int read()
{
    int v = 0, f = 1;
    char c = getchar();
    while (c < 48 || 57 < c) {if (c == '-') f = -1; c = getchar();}
    while (48 <= c && c <= 57) v = (v << 3) + v + v + c - 48, c = getchar();
    return v * f;
}

const int N = 300010;
const ll MOD = 998244353;
int n, q, B, B2;
int c[N], L[N], R[N], belong[N], d[N], now[N], mx[N], op[N][10], _c[N];
ll a[N], f[N], num[600][600], g[600][600];
set<int> S[N];

int main()
{
    freopen("color.in", "r", stdin);
    freopen("color.out", "w", stdout);
    n = read(), q = read();
    for (int i = 1; i <= n; i++)
    {
        c[i] = _c[i] = read();
        S[c[i]].insert(i);
        now[c[i]]++;
    }
    for (int i = 1; i <= n; i++)
        mx[i] = now[i];
    for (int i = 1; i <= q; i++)
    {
        op[i][0] = read();
        if (op[i][0] == 1)
        {
            op[i][1] = read();
            op[i][2] = read();
            op[i][3] = read();
            op[i][4] = read();
        }
        if (op[i][0] == 2)
        {
            op[i][1] = read();
            op[i][2] = read();
        }
        if (op[i][0] == 3)
        {
            op[i][1] = read();
            op[i][2] = read();
            now[_c[op[i][1]]]--;
            _c[op[i][1]] = op[i][2];
            now[op[i][2]]++;
            mx[op[i][2]] = max(mx[op[i][2]], now[op[i][2]]);
        }
    }
    B2 = sqrt(n + q + 0.5);
    int cnt = 0;
    for (int i = 1; i <= n; i++)
        if (mx[i] > B2)
            d[i] = ++cnt;
    B = sqrt(n + 0.5) + 2;
    for (int i = 1; i <= B; i++)
    {
        L[i] = (i - 1) * B + 1;
        R[i] = i * B;
        for (int j = L[i]; j <= R[i]; j++)
        {
            belong[j] = i;
            if (d[c[j]])
                num[i][d[c[j]]]++;
        }
    }
    for (int j = 1; j <= q; j++)
    {
        if (op[j][0] == 1)
        {
            int l = op[j][1], r = op[j][2], x = op[j][3];
            ll y = op[j][4];
            if (d[x])
            {
                if (belong[l] == belong[r])
                {
                    for (int i = l; i <= r; i++)
                        if (c[i] == x)
                        {
                            a[i] = (a[i] + y) % MOD;
                            f[belong[i]] = (f[belong[i]] + y) % MOD;
                        }
                } else
                {
                    for (int i = l; i <= R[belong[l]]; i++)
                        if (c[i] == x)
                        {
                            a[i] = (a[i] + y) % MOD;
                            f[belong[i]] = (f[belong[i]] + y) % MOD;
                        }
                    for (int i = belong[l] + 1; i <= belong[r] - 1; i++)
                    {
                        g[i][d[x]] = (g[i][d[x]] + y) % MOD;
                        f[i] = (f[i] + num[i][d[x]] * y) % MOD;
                    }
                    for (int i = L[belong[r]]; i <= r; i++)
                        if (c[i] == x)
                        {
                            a[i] = (a[i] + y) % MOD;
                            f[belong[i]] = (f[belong[i]] + y) % MOD;
                        }
                }
            } else
            {
                for (set<int> :: iterator i = S[x].begin(); i != S[x].end(); i++)
                {
                    int u = *i;
                    if (l <= u && u <= r)
                    {
                        a[u] = (a[u] + y) % MOD;
                        f[belong[u]] = (f[belong[u]] + y) % MOD;
                    }
                }
            }
        }
        if (op[j][0] == 2)
        {
            int l = op[j][1], r = op[j][2];
            ll ans = 0;
            if (belong[l] == belong[r])
            {
                for (int i = l; i <= r; i++)
                    if (d[c[i]])
                        ans = (ans + g[belong[i]][d[c[i]]] + a[i]) % MOD;
                    else
                        ans = (ans + a[i]) % MOD;
            } else
            {
                for (int i = l; i <= R[belong[l]]; i++)
                    if (d[c[i]])
                        ans = (ans + g[belong[i]][d[c[i]]] + a[i]) % MOD;
                    else
                        ans = (ans + a[i]) % MOD;
                for (int i = belong[l] + 1; i <= belong[r] - 1; i++)
                    ans = (ans + f[i]) % MOD;
                for (int i = L[belong[r]]; i <= r; i++)
                    if (d[c[i]])
                        ans = (ans + g[belong[i]][d[c[i]]] + a[i]) % MOD;
                    else
                        ans = (ans + a[i]) % MOD;
            }
            printf("%lld\n", ans);
        }
        if (op[j][0] == 3)
        {
            int x = op[j][1], y = op[j][2];
            if (d[c[x]])
            {
                a[x] = (a[x] + g[belong[x]][d[c[x]]]) % MOD;
                num[belong[x]][d[c[x]]]--;
            }
            S[c[x]].erase(x);
            c[x] = y;
            S[c[x]].insert(x);
            if (d[c[x]])
            {
                a[x] = (a[x] - g[belong[x]][d[c[x]]] + MOD) % MOD;
                num[belong[x]][d[c[x]]]++;
            }
        }
    }
}

test20181025 Color的更多相关文章

  1. 【转】c#、wpf 字符串,color,brush之间的转换

    转自:http://www.cnblogs.com/wj-love/archive/2012/09/14/2685281.html 1,将#3C3C3C 赋给background this.selec ...

  2. Python为8bit深度图像应用color map

    图片中存在着色版的概念,二维矩阵的每个元素的值指定了一种颜色,因此可以显示出彩色. 迁移调色板 下述python代码将VOC数据集中的某个语义分割的图片的调色板直接应用在一个二维矩阵代表的图像上 #l ...

  3. (转)System.Drawing.Color的颜色对照表

    经常使用System.Drawing.Color, 本篇介绍一下颜色与名称及RGB值的对应关系. 1. 颜色与名称的对照表(点击下图放大看): 2. 颜色与RGB值对照表: Color.AliceBl ...

  4. 激光打印机的Color/paper, Xerography介绍

    Color Basic 看见色彩三要素: 光源,物体,视觉 加色色彩模型:R,G,B 多用于显示器 减色色彩模型:C,M,Y,K 多用于打印复印 Paper 东亚地区常用A系列标准用纸,在多功能一体机 ...

  5. 安卓工具箱:color of Style

    <?xml version="1.0" encoding="utf-8"?> <resources> <color name=&q ...

  6. UITableView 一直显示滚动条(ScrollBar Indicators)、滚动条Width(宽度)、滚动条Color(颜色)

    在 IOS 中,对 UIScrollView 的滚动条(ScrollBar Indicators)的自定义设置接口,一直都是很少的.除了能自定义简单的样式(UIScrollViewIndicatorS ...

  7. OpenCASCADE Color Scale

    OpenCASCADE Color Scale eryar@163.com Abstract. The color scale is a specialized label object that d ...

  8. Color Transfer between Images code实现

    上计算机视觉课老师布置的作业实现论文:Color Transfer between Images 基本思路是: 1.给定srcImg和targetImg 2.将RGB空间转为Lab空间 3.根据论文中 ...

  9. ZOJ Problem Set - 1067 Color Me Less

    这道题目很简单,考察的就是结构体数组的应用,直接贴代码了 #include <stdio.h> #include <math.h> typedef struct color { ...

随机推荐

  1. 2017-2018 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2017) Solution

    A:Concerts 题意:给出一个串T, 一个串S,求串S中有多少个串T,可以重复,但是两个字符间的距离要满足给出的数据要求 思路:先顺序统计第一个T中的字符在S中有多少个,然后对于第二位的以及后面 ...

  2. Transactions and beyond it..

    While data integrity is managed very effectively within a single database with row locking, deadlock ...

  3. 【转】微信jssdk录音功能开发记录

    转自:http://www.cnblogs.com/liujunyang/p/4962423.html#undefined 0.需求描述 在微信浏览器内打开的页面,制作一个按钮,用户按住按钮后开始录音 ...

  4. JS地址自动返填技术

    系统设计地址为省市县三级联动,规范是规范了,但是无形中增加了系统操作的时间成本,因此设计地址自动返填技术,只要把地址拷贝到详细地址框中,可以自动返填到省市县三级联动的下拉框中. 还好洒家的大学不是混过 ...

  5. 2018-2019-1 20189215 《Linux内核原理与分析》第四周作业

    <庖丁解牛>第三章书本知识总结 计算机的三大法宝 存储程序计算机 函数调用堆栈 中断 操作系统的两把宝剑 中断上下文的切换--保存现场和恢复现场 进程上下文的切换 Linux内核源码的目录 ...

  6. 20155201 2016-2017-2 《Java程序设计》第一周学习总结

    20155201 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 每一章的问题: 第一章 Java ME都有哪些成功的平台? 第二章 哪些情况可以使用impo ...

  7. 20172305 2018-2019-1 《Java软件结构与数据结构》第七周学习总结

    20172305 2018-2019-1 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 本周内容主要为书第十一章内容: 二叉查找树(附加属性的二叉树) 二叉查找树是对树中 ...

  8. MFC各种属性定义及DLL使用理解

    ps:如果需要使用第三方动态库,需要下面几个因素配置 1.第三方库提供的源文件[C/C++,常规,附加包含目录] 2.动态库[和生成的exe放一起] 3.LIB文件的目录[链接器,附加库目录] 4.L ...

  9. [BZOJ1877][SDOI2009]SuperGCD

    题目大意 求两个个高精度数的gcd 题目解析 在学习gcd的时候,书上就记载了"更相减损术"这一方法 基于这种方法,我们进行优化,使得我们能快速求出两个大数的gcd 对于 \(a, ...

  10. 利用IntelliJ IDEA创建第一个Groovy工程

    因为某些原因,需要学习一下Groovy.关于Groovy的入门教程请看这篇文章http://www.ibm.com/developerworks/cn/education/java/j-groovy/ ...