题意


分析

自己的想法

可以莫队+平衡树。

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

区间加操作容易实现。

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

感谢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. echarts页面中多图自适应

    $(function (){ //ups部分 var myChart = echarts.init(document.getElementById('result')) var option = { ...

  2. 使用Vuejs编写单js组件

    1.引用方式 我们使用Vue进行普通页面开发却不使用webpack等技术时,定义组件可以只依赖单js文件进行开发 然后像正常引用js文件那样进行引用 <script src="../C ...

  3. 20145204《Java程序设计》第5周学习总结

    20145204<Java程序设计>第5周学习总结 教材学习内容总结 语法与继承构架 我们之前接触到的C通常都是将程序流程和错误处理混在一起,在编写程序的时候必须考虑可能出现的错误并提前做 ...

  4. 20145221 《Java程序设计》第七周学习总结

    20145221 <Java程序设计>第七周学习总结 教材学习内容总结 第十二章部分 - Lambda 认识Lambda语法 Lambda去可以重复,符合DRY原则,而且Lambda表达式 ...

  5. linux下如何使用split

    答: 切割文件hello,以每个文件最大10MiB来切割,切割好的文件名前缀为hello.,后缀为二位的数字,切割之后的名字为hello.01,hello.02等等    split -b 10M - ...

  6. Tinkoff Challenge - Elimination Round B. Igor and his way to work(dfs+优化)

    http://codeforces.com/contest/793/problem/B 题意:一个地图,有起点和终点还有障碍点,求从起点出发到达终点,经过的路径上转弯次数是否能不超过2. 思路: 直接 ...

  7. BZOJ 1875 【SDOI2009】 HH去散步

    题目链接:HH去散步 如果不考虑不能走上一次走的边的话,这道题就是一个矩乘的裸题. 现在有了这个条件其实也很好做.我们平常的矩阵都是按点建的,\(A_{i,j}\)表示从第\(i\)个点走到第\(j\ ...

  8. windows下利用批处理命令生成maven项目(java、javaWeb)

    觉得用IDE生成maven项目会卡住,很慢.就用cmd写了个cmd批处理命令来生成maven项目.效果如下 生成项目导入idea后结构如下 批处理命令代码如下 @echo off ::echo 请选择 ...

  9. JavaScript权威指南--WEB浏览器中的javascript

    知识要点 1.客户端javascript window对象是所有客户端javascript特性和API的主要接入点.它表示web浏览器的一个窗口或窗体,并且可以用window表示来引用它.window ...

  10. bzoj-4565-区间dp+状压

    4565: [Haoi2016]字符合并 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 542  Solved: 253[Submit][Status ...