Problem Statement

You are given a sequence $A=(A_1,\ldots,A_N)$ of length $N$. Each element is $0$, $1$, or $2$.

Process $Q$ queries in order. Each query is of one of the following kinds:

  • 1 L R: print the inversion number of the sequence $(A_L,\ldots,A_R)$.
  • 2 L R S T U: for each $i$ such that $L\leq i \leq R$, if $A_i$ is $0$, replace it with $S$; if $A_i$ is $1$, replace it with $T$; if $A_i$ is $2$, replace it with $U$.
What is the inversion number?

The inversion number of a sequence $B = (B_1, \ldots, B_M)$ is the number of pairs of integers $(i, j)$ $(1 \leq i < j \leq M)$ such that $B_i > B_j$.

Constraints

  • $1 \leq N \leq 10^5$
  • $0 \leq A_i \leq 2$
  • $1\leq Q\leq 10^5$
  • In each query, $1\leq L \leq R \leq N$.
  • In each query of the second kind, $0\leq S,T,U \leq 2$.
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

$N$ $Q$
$A_1$ $A_2$ $\ldots$ $A_N$
$\rm Query_1$
$\rm Query_2$
$\vdots$
$\rm Query_Q$

$\rm Query_i$ denotes the $i$-th query, which is in one of the following formats:

$1$ $L$ $R$
$2$ $L$ $R$ $S$ $T$ $U$

Output

Print the responses to the queries of the first kind in the given order, separated by newlines.


Sample Input 1

5 3
2 0 2 1 0
1 2 5
2 2 4 2 1 0
1 2 5

Sample Output 1

3
4

Initially, $A=(2,0,2,1,0)$.

  • In the $1$-st query, print the inversion number $3$ of $(A_2,A_3,A_4,A_5)=(0,2,1,0)$.
  • The $2$-nd query makes $A=(2,2,0,1,0)$.
  • In the $3$-rd query, print the inversion number $4$ of $(A_2,A_3,A_4,A_5)=(2,0,1,0)$.

Sample Input 2

3 3
0 1 2
1 1 1
2 1 3 0 0 0
1 1 3

Sample Output 2

0
0

区间修改区间询问,首先考虑线段树。

那么我们可以把一对逆序对分成两类,把线段用线段树分成一个个区间后,逆序对有些两个数在一个区间里,有些不在一个区间里。在一个区间里的逆序对,我们可以每次更新的时候都维护逆序对个数。而不再一个区间里的,我们可以在外面再跑一次

那么具体来说。首先不考虑修改,一个区间的逆序对数量需要分开来记录才好记录。记录 \(p_{i,j}\) 为这个区间中形如 \((i,j)\) 的有序数对有多少个。当然我们还要记录一个区间有多少个0,多少个1,多少个2.

线段树上两个区间合并时,节点 \(o\) 的有序数对 \((i,j)\) 的数量为左儿子 \((i,j)\) 的数量和右儿子 \((i,j)\) 的数量加上左区间 \(i\) 的数量和右区间 \(j\) 的数量之积。

区间修改自然还要打tag,记录这个区间中原有的 0 变成那个数字,1变成那个数字,2变成那个数字。这个 tag 也很好合并,更新时逐个数字更新就好了。

线段树的部分解决了,来看询问时的部分。询问时对于跨过区间的逆序对,我们可以记录在这个区间前面有多少个 0,有多少个 1,有多少个2,然后乘起来加上就好。

#include<bits/stdc++.h>
const int N=1e5+5;
typedef long long LL;
struct node{
int a[3],s,t,u;
LL b[3][3];
}tr[N<<2];
LL ret;
int n,op,l,r,s,t,u,q,x,a0,a1,a2;
void pushup(int o)
{
for(int i=0;i<3;i++)
tr[o].a[i]=tr[o<<1].a[i]+tr[o<<1|1].a[i];
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
tr[o].b[i][j]=tr[o<<1].b[i][j]+tr[o<<1|1].b[i][j]+1LL*tr[o<<1].a[i]*tr[o<<1|1].a[j];
}
void turn(int o,int s,int t,int u)
{
int a[3],p[3];
LL b[3][3];
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
p[0]=s,p[1]=t,p[2]=u;
for(int i=0;i<3;i++)
{
a[p[i]]+=tr[o].a[i];
for(int j=0;j<3;j++)
b[p[i]][p[j]]+=tr[o].b[i][j];
}
memcpy(tr[o].a,a,sizeof(a));
memcpy(tr[o].b,b,sizeof(b));
}
void add(int o,int s,int t,int u)
{
if(tr[o].s==-1)
tr[o].s=s,tr[o].t=t,tr[o].u=u;
else
{
int p[3]={s,t,u};
tr[o].s=p[tr[o].s];
tr[o].t=p[tr[o].t];
tr[o].u=p[tr[o].u];
}
}
void pushdown(int o)
{
if(tr[o].s!=-1)
{
turn(o<<1,tr[o].s,tr[o].t,tr[o].u);
turn(o<<1|1,tr[o].s,tr[o].t,tr[o].u);
add(o<<1,tr[o].s,tr[o].t,tr[o].u);
add(o<<1|1,tr[o].s,tr[o].t,tr[o].u);
tr[o].s=tr[o].t=tr[o].u=-1;
}
}
void solve(int o,int l,int r)
{
if(l>r)
return;
if(l==r)
{
scanf("%d",&x);
tr[o].a[x]++;
return;
}
int md=l+r>>1;
solve(o<<1,l,md);
solve(o<<1|1,md+1,r);
pushup(o);
tr[o].s=tr[o].t=tr[o].u=-1;
}
LL query(int o,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
ret+=1LL*a2*tr[o].a[1];
ret+=1LL*a1*tr[o].a[0];
ret+=1LL*a2*tr[o].a[0];
a0+=tr[o].a[0];
a1+=tr[o].a[1];
a2+=tr[o].a[2];
return tr[o].b[2][1]+tr[o].b[2][0]+tr[o].b[1][0];
}
pushdown(o);
int md=l+r>>1;
LL ret=0;
if(md>=x)
ret+=query(o<<1,l,md,x,y);
if(md<y)
ret+=query(o<<1|1,md+1,r,x,y);
return ret;
}
void update(int o,int l,int r,int x,int y,int s,int t,int u)
{
if(x<=l&&r<=y)
{
turn(o,s,t,u);
add(o,s,t,u);
return;
}
pushdown(o);
int md=l+r>>1;
if(md>=x)
update(o<<1,l,md,x,y,s,t,u);
if(md<y)
update(o<<1|1,md+1,r,x,y,s,t,u);
pushup(o);
}
int main()
{
scanf("%d%d",&n,&q);
solve(1,1,n);
while(q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r),ret=a0=a1=a2=0;
printf("%lld\n",query(1,1,n,l,r)+ret);
}
else
{
scanf("%d%d%d%d%d",&l,&r,&s,&t,&u);
update(1,1,n,l,r,s,t,u);
}
}
}

[ABC265G] 012 Inversion的更多相关文章

  1. HDU 1394 Minimum Inversion Number ( 树状数组求逆序数 )

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number                         ...

  2. 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)

    控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...

  3. HDU 1394 Minimum Inversion Number(最小逆序数 线段树)

    Minimum Inversion Number [题目链接]Minimum Inversion Number [题目类型]最小逆序数 线段树 &题意: 求一个数列经过n次变换得到的数列其中的 ...

  4. 依赖倒置原则(Dependency Inversion Principle)

    很多软件工程师都多少在处理 "Bad Design"时有一些痛苦的经历.如果发现这些 "Bad Design" 的始作俑者就是我们自己时,那感觉就更糟糕了.那么 ...

  5. HDU 1394 Minimum Inversion Number(最小逆序数/暴力 线段树 树状数组 归并排序)

    题目链接: 传送门 Minimum Inversion Number Time Limit: 1000MS     Memory Limit: 32768 K Description The inve ...

  6. Inversion Sequence(csu 1555)

    Description For sequence i1, i2, i3, … , iN, we set aj to be the number of members in the sequence w ...

  7. ACM: 强化训练-Inversion Sequence-线段树 or STL·vector

    Inversion Sequence Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%lld & %llu D ...

  8. ACM Minimum Inversion Number 解题报告 -线段树

    C - Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  9. HDU-Minimum Inversion Number(最小逆序数)

    Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of ...

  10. 【hdu1394】Minimum Inversion Number

    Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of ...

随机推荐

  1. devops之Python编程-类的基础架构

    Python中,可以通过关键字class来定义一个类.类是一种自定义数据类型,它可以包含属性(变量)和方法(函数).下面是一个示例: class MyClass: def __init__(self, ...

  2. QA|重写了元素定位后报错xx object has no attribute 'find_element'|网页计算器自动化测试实战

    代码如下: 1 # basepage.py 2 3 from selenium import webdriver 4 5 6 class BasePage(): 7 """ ...

  3. brpc internal

    brpc 内部实现 thread model pthread 1:1atomic cache同步降低性能 fiber n:1 -> nginx 多核难以扩展, 用户不能做阻塞操作. contex ...

  4. 企业级低代码平台,通用代码生成平台,Java开源项目(附源码)

    项目介绍 Jeecg-Boot 是一款基于代码生成器的智能开发平台!采用前后端分离架构:SpringBoot,Mybatis,Shiro,JWT,Vue&Ant Design.强大的代码生成器 ...

  5. LeetCode155:最小栈,最简单的中等难度题,时间击败100%,内存也低于官方

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 最近运气不错,在LeetCode上白捡一道送 ...

  6. MySQL系列之备份恢复——运维在备份恢复方面、备份类型、备份方式及工具、逻辑备份和物理备份、备份策略、备份工具使用-mysqldump、企业故障恢复案例、备份时优化参数、MySQL物理备份工具

    文章目录 1. 运维在数据库备份恢复方面的职责 1.1 设计备份策略 1.2 日常备份检查 1.3 定期恢复演练(测试库) 1.4 故障恢复 1.5 迁移 2. 备份类型 2.1 热备 2.2 温备 ...

  7. win11系统无法解决的死结

    如果需要使用网上银行.win11一定不能使用. win11已经取消了,对于IE浏览器的支持和安装. 但是大部分网银都是要求IE浏览器.或者IE内核.实际过程当中.虽然所有的浏览器都说兼容IE有IE内核 ...

  8. 深入MySQL索引,这篇千万不能错过

    大家好,我是[码老思],索引是一个数据库绕不开的话题,今天和大家一起聊聊. 1. 索引 索引是对数据库表中一列或多列的值进行排序的一种结构. MySQL索引的建立对于MySQL的高效运行是很重要的,索 ...

  9. Anaconda虚拟环境配置Python库与Spyder编译器

      本文介绍在Anaconda中,为Python的虚拟环境安装第三方库与Spyder等配套软件的方法.   在文章创建Anaconda虚拟Python环境的方法中,我们介绍了在Anaconda环境下, ...

  10. C#/.NET/.NET Core优秀项目和框架精选(2023年10月更新,项目分类已整理完成欢迎大家踊跃提交PR一起完善让优秀的项目和框架不被埋没)

    前言 帮助开发者发现功能强大.性能优越.创新前沿.简单易用的C#/.NET/.NET Core优秀项目和框架,无论你是寻找灵感.学习新技术.改进代码质量,还是想拓展自己的技术视野,都能为你提供有价值的 ...