Description

小 a有一个长度无限长的序列 p = (1, 2, 3, 4 ……),初始时 pi = i

给出 m 个操作,每次交换两个位置的数

询问最后序列逆序对的个数

Solution

忘了可以树状数组直接做了.所以写了很麻烦的线段树.

大概写一下怎么做, 因为细节比较多.

我们发现一次交换的实际上是交换了两个位置上的数.

我们可以将所有的位置分成三类:

  • 有的位置会被改变(交换), 也对答案有贡献;

  • 有的位置不会被改变, 也不会对答案有贡献;

  • 有的位置不会被改变, 但是对答案有贡献.

  • 第一类是所有的操作会交换的位置;

  • 第二类是被改变的第一个和最后一个位置往左和往右的数;

  • 第三类是不会被直接改变, 但是其左右都有被改变的数.

举个例子:交换2和5位置, 数列变成\(1,5,3,4,2,6,7,\cdots\).

位置\(2, 5\)属于第一类, 位置\(1,6,7,\cdots\)属于第二类, 位置\(3, 4\)属于第三类(因为与5位置形成逆序对)

  • 对于不会被改变也没有影响的数, 忽略存在就好了.
  • 对于不会被改变但是有影响的位置, 这些位置的行为表现出来像是一个整体(会同时对另一个位置产生或不产生逆序对).

    所以就把他们起来, 看成是一个特殊的数字就好了.

所以就将这些涉及到的位置离散化, 在离散化后按要求交换这些位置上的数形成一个数列,利用树状数组/线段树求逆序对即可.

至于怎么离散化, 看代码就好了

Code

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6;
struct Node {
long long val;
Node *ls, *rs;
Node(int _v = 0, Node *_ls = nullptr, Node *_rs = nullptr) :
val(_v), ls(_ls), rs(_rs) { }
void pushup() {
val = ls->val + rs->val;
}
void mod(int k) { val += k; }
};
class Tree { // 普通的单调修改区间查询线段树
int n;
Node* root;
#define LS l, mid, node->ls
#define RS mid + 1, r, node->rs
void build(int l, int r, Node* node) {
if (l == r) return;
int mid = l + r >> 1;
node->ls = new Node();
node->rs = new Node();
build(LS), build(RS);
}
void insert(int l, int r, Node* node, int p, int k) {
if (l == r) return node->mod(k);
int mid = l + r >> 1;
if (p <= mid) insert(LS, p, k);
if (p > mid) insert(RS, p, k);
node->val = node->ls->val + node->rs->val;
}
long long query(int l, int r, Node* node, int L, int R) {
if (l >= L and r <= R)
return node->val;
int mid = l + r >> 1;
long long res = 0;
if (L <= mid) res += query(LS, L, R);
if (R > mid) res += query(RS, L, R);
return res;
}
public:
Tree(int _n) : n(_n), root(new Node()) {}
void build() {
build(1, n, root);
}
long long query(int l, int r) {
return query(1, n, root, l, r);
}
void insert(int p, int k) {
insert(1, n, root, p, k);
}
};
struct Operate {
int l, r;
Operate(int _ = 0, int __ = 0) :
l(_), r(__) {}
}Opt[N];
struct Element {
int v, siz;
Element(int _v = 0, int _s = 0) :
v(_v), siz(_s) { }
bool operator < (const Element& o) const {
return v < o.v;
}
}P[N]; int A[N], seq[N]; int main () {
int n;
scanf("%d", &n);
int tot = 0;
for (int i = 1, u, v, c; i <= n; i += 1) {
scanf("%d%d", &u, &v);
Opt[i] = Operate(u, v);
A[++tot] = u, A[++tot] = v;
}
sort(A + 1, A + tot + 1);
int cnt = unique(A + 1, A + tot + 1) - A - 1; // 被直接交换的位置, 也就是第一类
int total = 0;
for (int i = 1; i <= cnt; i += 1) {
P[++total] = Element(A[i], 1); // 第一类
if (A[i + 1] > A[i] + 1) // A[i] 和A[i+1]之间的是第三类
P[++total] = Element(A[i] + 1, A[i + 1] - A[i] - 1); // A[i+1]-A[i]-1是这一段的个数
}
#define Find(x) lower_bound(P + 1, P + total + 1, Element(x, 0)) - P
Tree* T = new Tree(total); // 建线段树
T->build();
for (int i = 1; i <= total; i += 1)
seq[i] = i;
for (int i = 1, u, v; i <= n; i += 1) {
u = Find(Opt[i].l), v = Find(Opt[i].r); // 按要求交换
swap(seq[u], seq[v]);
}
long long res = 0;
for (int i = 1; i <= total; i += 1) {
T->insert(seq[i], P[seq[i]].siz);
res += 1ll * P[seq[i]].siz * T->query(seq[i] + 1, total);
}
printf("%lld\n", res);
return 0;
}

P2448 无尽的生命的更多相关文章

  1. P2448 无尽的生命(树状数组+离散化)

    题目描述 逝者如斯夫,不舍昼夜! 叶良辰认为,他的寿命是无限长的,而且每天都会进步. 叶良辰的生命的第一天,他有1点能力值.第二天,有2点.第n天,就有n点.也就是S[i]=i 但是调皮的小A使用时光 ...

  2. 杂项 List

    题目 1. 栈    #A 表达式的转换 (Unaccepted) 2. STL 模板库 #B 双栈排序(Unaccepted)    #C 垃圾陷阱(Accepted)    #D 合并果子(Acc ...

  3. Linux内核同步

    Linux内核剖析 之 内核同步 主要内容 1.内核请求何时以交错(interleave)的方式执行以及交错程度如何. 2.内核所实现的基本同步机制. 3.通常情况下如何使用内核提供的同步机制. 内核 ...

  4. Unity脚本生命周期

    前言 说到生命周期,影响最深刻的是,在接触Java的JSF组件时,JSF组件的五大生命周期,全要默写出来,嘿嘿…… 总结这两天在写小怪和掉落的糖葫芦时,老是遇到GameObject未销毁,一直存在场景 ...

  5. GPU大百科全书 第二章 凝固生命的光栅化

    光栅化——死神来了……   前言:在上一期的GPU大百科全书里,我们目睹了可爱的香草从抽象世界走向现实,从方程还原成实体的全过程.可以说香草活了,因为几何单元,我们赋予了她完整的灵魂. 如果你正在为G ...

  6. 从BeanFactory源码看Bean的生命周期

    下图是我搜索"Spring Bean生命周期"找到的图片,来自文章--Spring Bean的生命周期 下面,我们从AbstractAutowireCapableBeanFacto ...

  7. react组件的生命周期

    写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...

  8. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  9. C# MVC 5 - 生命周期(应用程序生命周期&请求生命周期)

    本文是根据网上的文章总结的. 1.介绍 本文讨论ASP.Net MVC框架MVC的请求生命周期. MVC有两个生命周期,一为应用程序生命周期,二为请求生命周期. 2.应用程序生命周期 应用程序生命周期 ...

随机推荐

  1. C++运算符重载形式——成员函数or友元函数

    运算符重载是C++多态的重要实现手段之一.通过运算符重载对运算符功能进行特殊定制,使其支持特定类型对象的运算,执行特定的功能,增强C++的扩展功能. 运算符重载的我们需要坚持四项基本原则: (1)不可 ...

  2. 解题:SDOI 2017 数字表格

    题面 反演题,推式子么=.= $\prod\limits_{d=1}^{min(n,m)}\prod\limits_{i=1}^n\prod\limits_{j=1}^m[gcd(i,j)==d]fi ...

  3. servlet与tomcat的关系

    1.4   Tomcat简介 学习Servlet技术,首先需要有一个Servlet运行环境,也就是需要有一个Servlet容器,本书采用的是Tomcat. Tomcat是一个免费的开放源代码的Serv ...

  4. R语言画图

    转http://www.cnblogs.com/jiangmiaomiao/p/6991632.html 0 引言 R支持4种图形类型: base graphics, grid graphics, l ...

  5. intval floatval

    intval -- 获取变量的整数值 floatval -- 获取变量的浮点值 <?php $a = ; $b = ; $a/=$b; echo intval($a); echo floatva ...

  6. STL中的优先级队列priority_queue

    priority_queue(queue类似)完全以底部容器为根据,再加上二叉堆(大根堆或者小根堆)的实现原理,所以其实现非常简单,缺省情况下priority_queue以vector作为底部容器.另 ...

  7. Python【time】模块

    import timeprint(type(11.234))print("输出结果为时间戳,float类型:",time.time())print("输出结果为本地时间元 ...

  8. 「Vue」自定义按键修饰符

    vue.config.keyCodes.f2 = 113 设置完成后就可以绑定f2的按键操作@keyup.f2="add" 自带的有enter esc delete 空格 上下左右 ...

  9. python 调用aiohttp

    1. aiohttp安装   pip3 install aiohttp 1.1. 基本请求用法 async with aiohttp.get('https://github.com') as r: a ...

  10. Java基础-IO流对象之打印流(PrintStream与PrintWriter)

    Java基础-IO流对象之打印流(PrintStream与PrintWriter) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.打印流的特性 打印对象有两个,即字节打印流(P ...