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. 面向对象高级编程(2)-使用@property

    使用@property 在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改: s = Student() s.score = 9999 这显然不合逻 ...

  2. java的序列化流和打印流

    对象操作流(序列化流) 每次读取和写出的都是JavaBean对象. 序列化:将对象写入到文件中的过程 反序列化:从文件中读取对象到程序的过程 transient: 标识瞬态,序列化的时候,该修饰符修饰 ...

  3. Activity的setResult方法

    Activity的setResult方法http://blog.csdn.net/dinglin_87/article/details/8970144 调用setResult()方法必须在finish ...

  4. python反射,单例模式

    # getattr# hasattr# setattr# delattr class Foo: def __init__(self, name,age): self.name = name self. ...

  5. js原型解释图

  6. 详解 Cookie 纪要(vue.cookie,jquery.cookie简化)

    今天看到一篇cookie的文章,写的特别详细,感谢 晚晴幽草轩 的分享,原文链接http://www.jeffjade.com/2016/10/31/115-summary-of-cookie/ 原文 ...

  7. 安装解压版的mariadb

    今天尝试了安装解压版的mariadb,在官网上https://downloads.mariadb.org/下载了5.5版本的mariadb的zip压缩包, 经过实践发现mariadb解压版安装与mys ...

  8. 2017 清北济南考前刷题Day 1 morning

    期望得分:100+100+50=250 实际得分:100+60+50=210 T2 二分 估错上界.估错复杂度 T1 立方数(cubic) Time Limit:1000ms   Memory Lim ...

  9. js事件的捕获和冒泡阶段

    讨论的主要是两个事件模型:IE事件模型与DOM事件模型 IE内核浏览器的事件模型是冒泡型事件(没有捕获事件过程),事件句柄的触发顺序是从ChildNode到ParentNode. <div id ...

  10. php设计模式之工厂设计模式

    概念:        工厂设计模式提供获取某个对象的新实例的一个接口,同时使调用代码避免确定实际实例化基类步骤. 很多高级模式都是依赖于工厂模式. 好处:         PHP中能够创建基于变量内容 ...