题意


分析

自己的想法

可以莫队+平衡树。

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

区间加操作容易实现。

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

感谢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. 使用spring cache和ehcache之前必须了解的

    好长时间没写博客了,真的是没时间啊.ps:其实就是懒!!接下来几篇要写下缓存,这里主要写下ehcache与spring整合的内容,包括aop形式的缓存,基于注解的缓存,页面缓存这三方面吧.在这之前先要 ...

  2. Mysql优化原则_小表驱动大表IN和EXISTS的合理利用

    //假设一个for循环 ; $i < ; $i++) { ; $i < ; $j++) { } } ; $i < ; $i++) { ; $i < ; $j++) { } } ...

  3. P1052 过河(离散化+dp)

    P1052 过河 dp不难,重点是要想到离散化. 石子个数$<=100$意味着有大量空间空置,我们可以缩掉这些空间. 实现的话自己yy下就差不多了. #include<iostream&g ...

  4. sqlite中的时间

    插入时间的sql语句 ','-61') 时间格式'2014-11-17T19:37:32' 年月日和时分秒之间多了一个字母T,保存到数据库的时候,会自动给时间加8个小时. 保存的结果为2014-11- ...

  5. JQuery中width和JS中JS中关于clientWidth offsetWidth scrollWidth 等的含义

    JQuery中: width()方法用于获得元素宽度: innerWidth()方法用于获得包括内边界(padding)的元素宽度: outerWidth()方法用于获得包括内边界(padding)和 ...

  6. ipconfig会出现多个IP地址

    一.问题描述 今天调试程序的时候发现电脑有两个IP地址,一时间不知道该用哪个?如下图: 二.问题分析 第一个叫ppp适配器,是一个逻辑的虚拟设备,ppp的意思是Point-to-Point Proto ...

  7. JavaScript--语法4--函数1

    JavaScript--语法4--函数1 一.心得 二.代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" " ...

  8. MongoDB排序异常

    com.mongodb.MongoQueryException: Query failed with error code 96 and error message 'Executor error d ...

  9. sshpass使用

    sshpass的使用方法 应用范围:可以在命令行直接使用密码来进行远程连接和远程拉取文件. 使用前提:对于未连接过的主机.而又不输入yes进行确认,需要进行sshd服务的优化: # vim /etc/ ...

  10. gitlab访问限制问题------Forbidden

    解决方案: cd /etc/gitlab vim /gitlab.rb gitlab_rails['rack_attack_git_basic_auth'] = { 'enabled' => t ...