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. SpringBoot 启动流程追踪(第二篇)

    上一篇文章分析了除 refresh 方法外的流程,并着重分析了 load 方法,这篇文章就主要分析 refresh 方法,可以说 refresh 方法是 springboot 启动流程最重要的一环,没 ...

  2. CSS实现文字描边效果

    一.介绍最近在一个项目的宣传页中,设计师使用了文字描边效果,之前我确实没有实现过文字的描边效果,然后我在查阅资料后,知道了实现方法.文字描边分为两种:内外双描边和单外描边,也就是指在给文字加上描边效果 ...

  3. 如何利用AI智能聊天机器人10秒钟做出一个故事绘本的神奇插件

    原文链接:如何利用AI智能聊天机器人10秒钟做出一个故事绘本的神奇插件 ChatGPT以下称为AI智能聊天机器人 一.AI智能聊天机器人4中集成"Stories"插件 对于已经熟悉 ...

  4. 初级线段树 POJ3264

    Balanced Lineup Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line ...

  5. Java 中的日期时间总结

    前言 大家好,我是 god23bin,在日常开发中,我们经常需要处理日期和时间,日期和时间可以说是一定会用到的,现在总结下 Java 中日期与时间的基本概念与一些常用的用法. 基本概念 日期(年月日, ...

  6. Visual Studio必备插件

    1.Rainbow Braces 2.Codist 3.ResXManager 4.XAML Styler for Visual Studio 2022 5.Viasfora 6.ZenCoding ...

  7. 使用TorchLens可视化一个简单的神经网络

      TorchLens:可用于可视化任何PyTorch模型,一个包用于在一行代码中提取和映射PyTorch模型中每个张量运算的结果.TorchLens功能非常强大,如果能够熟练掌握,算是可视化PyTo ...

  8. Springboot中使用线程池的三种方式

    前言 多线程是每个程序员的噩梦,用得好可以提升效率很爽,用得不好就是埋汰的火葬场. 这里不深入介绍,主要是讲解一些标准用法,熟读唐诗三百首,不会作诗也会吟. 这里就介绍一下springboot中的多线 ...

  9. modbus转profinet网关连接UV系列流量计程序实例

    modbus转profinet网关连接UV系列流量计程序实例 用户现场是西门子1200PLC通过兴达易控Modbus转Profinet网关连接流量计的配置,对流量瞬时值及报警值监控及控制程序案例 硬件 ...

  10. DB2复制表结构及数据

    在DB2数据库中,复制已经存在的表的结构及其数据.我们采用两步走方式:第一步先复制表结构,第二部拷贝数据. 第一步:复制表结构 方法一: Create table test_Rate as (sele ...