CF785CAnton and Permutation(分块 动态逆序对)
Anton likes permutations, especially he likes to permute their elements. Note that a permutation of n elements is a sequence of numbers {a1, a2, ..., an}, in which every number from 1 to n appears exactly once.
One day Anton got a new permutation and started to play with it. He does the following operation q times: he takes two elements of the permutation and swaps these elements. After each operation he asks his friend Vanya, how many inversions there are in the new permutation. The number of inversions in a permutation is the number of distinct pairs (i, j) such that 1 ≤ i < j ≤ n and ai > aj.
Vanya is tired of answering Anton's silly questions. So he asked you to write a program that would answer these questions instead of him.
Initially Anton's permutation was {1, 2, ..., n}, that is ai = i for all i such that 1 ≤ i ≤ n.
Input
The first line of the input contains two integers n and q (1 ≤ n ≤ 200 000, 1 ≤ q ≤ 50 000) — the length of the permutation and the number of operations that Anton does.
Each of the following q lines of the input contains two integers li and ri (1 ≤ li, ri ≤ n) — the indices of elements that Anton swaps during the i-th operation. Note that indices of elements that Anton swaps during the i-th operation can coincide. Elements in the permutation are numbered starting with one.
Output
Output q lines. The i-th line of the output is the number of inversions in the Anton's permutation after the i-th operation.
Example
5 4
4 5
2 4
2 5
2 2
1
4
3
3
2 1
2 1
1
6 7
1 4
3 5
2 3
3 3
3 6
2 1
5 1
5
6
7
7
10
11
8
Note
Consider the first sample.
After the first Anton's operation the permutation will be {1, 2, 3, 5, 4}. There is only one inversion in it: (4, 5).
After the second Anton's operation the permutation will be {1, 5, 3, 2, 4}. There are four inversions: (2, 3), (2, 4), (2, 5) and (3, 4).
After the third Anton's operation the permutation will be {1, 4, 3, 2, 5}. There are three inversions: (2, 3), (2, 4) and (3, 4).
After the fourth Anton's operation the permutation doesn't change, so there are still three inversions.
题意:
初始数列,a[]为顺序排列。问每次交换u,v两个位置的数字后,逆序对数量。
由于数状数组解决逆序对是离线操作,不支持交换操作(就我所知是如此)。反正不好快速查询u,v位置的数和之间的数大小关系。
所以用分块乱搞,如果u,v距离不远,暴力即可,如果太远,可以用分块好的有序数组快速得到排名关系。每一次操作O(lg+sqrt)。
感觉不难实现,而且马上打CF了,所以难得写一遍了。
不过有序vector的删除和加入以前倒是没有实现过,get。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#define ps push_back
#define Siz(x) (int)x.size()
using namespace std;
typedef long long LL;
LL ans = 0LL;
const int maxn = + ;
int n,q; //n个数,m个操作
int num; //num个块
int block; // 块的长度
int L[maxn], R[maxn]; //每个块的左右边界
int a[maxn]; //n个数,用与单个比较
int belong[maxn]; //位置属于哪一块
vector<int> bit[maxn]; //每个块,用于lower_bound快速找个数。
void init(){
block=sqrt(n);
num=(n-)/block+;
for (int i=;i<=num;i++){
L[i]=(i-)*block+;
R[i]=i*block;
} R[num]=n; //修改细节
for(int i=;i<=n;i++)
belong[i]=(i-)/block + ;
for(int i=;i<=num;i++)
for (int j=L[i];j<=R[i];j++)
bit[i].ps(j); //每一块的有序序列
}
int query(int l,int r,int v){
if (l>r) return ;
int ans=;
if(belong[l]==belong[r]){
for(int i=l;i<=r;++i)
if(a[i]<v) ++ans;
return ans;
}
int id=belong[l];
for(int i=l;i<=R[id];++i){
if(a[i]<v) ans++;
}
for(int i=belong[l]+;i<=belong[r]-;i++){
int p2=lower_bound(bit[i].begin(),bit[i].end(),v)-bit[i].begin();
ans+=p2;
}
id=belong[r];
for(int i=L[id];i<=r;i++){
if(a[i]<v) ans++;
}
return ans;
}
void update(int l,int r){
int uu=a[l];
int vv=a[r];
int id=belong[l];
bit[id].erase(lower_bound(bit[id].begin(),bit[id].end(),uu));//删去。
bit[id].insert(upper_bound(bit[id].begin(),bit[id].end(),vv),vv);//加入
id = belong[r];
bit[id].erase(lower_bound(bit[id].begin(),bit[id].end(),vv));
bit[id].insert(upper_bound(bit[id].begin(),bit[id].end(),uu),uu);
swap(a[l],a[r]);
}
int main(){
scanf("%d %d",&n, &q);
for (int i=;i<=n;i++) a[i] = i;
init();
while(q--){
int u,v;
scanf("%d%d",&u,&v);
if(u==v){
printf("%lld\n",ans);
continue;
}
if(u>v) swap(u,v);
int t1=query(u+,v-,a[u]);//期间比左边小的
int t2=v--u-+-t1;//期间比左边大的
ans-=t1; ans+=t2;
t1=query(u+,v-,a[v]);
t2=v--u-+-t1;
ans+=t1; ans-=t2;
if(a[u]<a[v])++ans;
else ans--;
printf("%lld\n",ans);
update(u,v);
}
return ;
}
CF785CAnton and Permutation(分块 动态逆序对)的更多相关文章
- Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2886 Solved: 924[Submit][Stat ...
- BZOJ 3295: [Cqoi2011]动态逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3865 Solved: 1298[Submit][Sta ...
- 【Luogu1393】动态逆序对(CDQ分治)
[Luogu1393]动态逆序对(CDQ分治) 题面 题目描述 对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i < j的有序对(i,j)的个数.你需要计算出一个序 ...
- 【BZOJ3295】动态逆序对(线段树,树状数组)
[BZOJ3295]动态逆序对(线段树,树状数组) 题面 Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的 ...
- bzoj3295[Cqoi2011]动态逆序对 树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5987 Solved: 2080[Submit][Sta ...
- cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )
hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...
- P3157 [CQOI2011]动态逆序对(树状数组套线段树)
P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...
- P3157 [CQOI2011]动态逆序对
P3157 [CQOI2011]动态逆序对 https://www.luogu.org/problemnew/show/P3157 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai&g ...
- 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...
随机推荐
- uva 1493 - Draw a Mess(并查集)
题目链接:uva 1493 - Draw a Mess 题目大意:给定一个矩形范围,有四种上色方式,后面上色回将前面的颜色覆盖,最后问9种颜色各占多少的区域. 解题思路:用并查集维护每一个位置相应下一 ...
- List集合的遍历方法
估计你永远都不会忘记这三个方法了...... public static void main(String[] args) { //超级for循环遍历方法 List<String> lis ...
- JavaScript 作用域链图具体解释
<script type="text/javascript"> /** * 作用域链: */ var a = "a"; function hao94 ...
- java中 ExecutorService,Executor,ThreadPoolExecutor的用法
package com; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import ...
- java String概述
class StringDemo { public static void main(String[] args) { String s1 = "abc";//s1 是一个类类 ...
- A、B两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成n段,由A、B开始轮流从最左端或最右端占据一段,直到分完为止。 马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)
第一种做法:这种方法,算法复杂性大,重复的递归 #include "stdafx.h" #include<iostream> #include<vector> ...
- JavaScript读书笔记(5)-Object Date
1.Object类型 (1)创建Object实例 第一种方式:new操作符后跟Object构造函数 var person=new Object(); person.name=”Nicholas”; p ...
- KEIL下分散加载文件的使用(zt)
KEIL下分散加载文件的使用 对于分散加载的概念,在<ARM体系结构与编程>书中第11章有明确介绍. 分散加载文件(即scatter file 后缀为.scf)是一个文本文件,通过编写 ...
- 导出到Excel中NPOI
源地址:http://www.cnblogs.com/dreamof/archive/2010/06/02/1750151.html\ 1.NPOI官方网站:http://npoi.codeplex. ...
- windows 2008配置运行PHP5.5.X
1.安装web5.0平台安装程序.web5.0平台安装程序:http://www.iis.net/downloads (实际上更方便的是用WebPlalform安装PHP:http://www.mic ...