codeforces 785 E. Anton and Permutation(分块)
来源:互联网 发布:环太平洋配乐 知乎 编辑:程序博客网 时间:2024/06/01 13:18
参考了某神牛的博客:http://blog.csdn.net/aozil_yang/article/details/62396346
题意:
给你一个只包好1-n的数的数列,初始为a[i]=i。有q次操作,每次操作把位置a,b的数交换,问每次操作后序列存在的逆序对数。
思路:
算法太渣,根本不知道有分块这种东西,今天第一次见识到。
分块,顾名思义就是把序列或者操作数分块,在这里我们可以把序列分成sqrt(n)块来做。这样分块的好处是什么呢,既维护了数与数之间的相对位置关系,右能对块内的数排序然后二分查找,缩短查找速度。
比如这个题,我们要交换位置a,b(a<b)的数,那我们就可以对于a,b中间整块的元素去二分第一个大于arr[a]的位置,就能得到这些块中小与arr[a]的数,而对于不在块内的我们只需要暴力去跑一遍求出小于arr[a]的数即可,这样就能求出区间(a,b)内小于arr[a]的数的个数,显然这样暴力跑的复杂度也是小于O(2*sqrt(n))的,二分的时间复杂度就更小了,所以只需要这样去查询即可。
更新的时候,由于一开始就是排好序的,我们每次更新又只改变了两个数的位置,那么使用插入排序自然是最快的。
代码:
#include <bits/stdc++.h>#define ps push_back#define LL long longusing namespace std;const int maxn=2e5+5;int n, q;int belong[maxn];int L[maxn];int R[maxn];int a[maxn];vector<int>blo[maxn>>1];void init(){ int block=sqrt(n); int num=n/block; if(n%block!=0)num++; int i, j; for(i=1; i<=num; i++) { L[i]=(i-1)*block+1; R[i]=i*block; } for(i=1; i<=n; i++) { belong[i]=(i-1)/block+1; } for(i=1; i<=num; i++) { for(j=L[i]; j<=R[i]; j++) { blo[i].ps(j); } } return;}int query(int l, int r, int v){ if(l>r)return 0; int i, j; int res=0; if(belong[l]==belong[r]) { for(i=l; i<=r; i++) { if(a[i]<v)res++; } return res; } int id=belong[l]; for(i=l; i<=R[id]; i++) { if(a[i]<v)res++; } int p; for(i=belong[l]+1; i<belong[r]; i++) { p=upper_bound(blo[i].begin(), blo[i].end(), v)-blo[i].begin(); res+=p; } for(i=L[belong[r]]; i<=r; i++) { if(a[i]<v)res++; } return res;}void update(int u, int v){ int uu=a[u]; int vv=a[v]; int i, j; int id=belong[u]; blo[id].erase(lower_bound(blo[id].begin(), blo[id].end(), uu)); blo[id].insert(upper_bound(blo[id].begin(), blo[id].end(), vv),vv); id=belong[v]; blo[id].erase(lower_bound(blo[id].begin(), blo[id].end(), vv)); blo[id].insert(upper_bound(blo[id].begin(), blo[id].end(), uu), uu); swap(a[u], a[v]);}int main(){ cin>>n>>q; init(); int i, j, x, y; for(i=1; i<=n; i++)a[i]=i; LL ans=0; for(i=0; i<q ; i++) { scanf("%d%d", &x, &y); if(x==y) { printf("%lld\n", ans); continue; } if(x>y)swap(x, y); int t1=query(x+1, y-1, a[x]); //交换后要损失的逆序对数,即区间内小于a[x]的数 下反 int t2=(y-1-x-1+1)-t1; //交换后新生成的逆序对数 , 即区间内大于a[x]的数 下反 // printf("%d %d\n", t1, t2); ans-=t1; ans+=t2; t1=query(x+1, y-1, a[y]); t2=(y-1-x-1+1)-t1;// printf("y%d %d %d\n", a[y], t1, t2); ans+=t1; ans-=t2; if(a[x]<a[y])ans++; else ans--; printf("%lld\n", ans); update(x, y); }}
0 0
- CodeForces 785E Anton and Permutation 分块
- codeforces 785 E. Anton and Permutation(分块)
- CodeForces 785E Anton and Permutation (分块)
- Codefores 785E Anton and Permutation(分块)
- codeforces 785E. Anton and Permutation
- codeforces 785 E. Anton and Permutation
- Codeforces Round #404 (Div. 2) -- E. Anton and Permutation(分块xjb 搞)
- Codeforces Round #404 (Div. 2)E. Anton and Permutation(分块)
- Codeforces Round #404 (Div. 2):E. Anton and Permutation(分块)
- Codeforces-785E-Anton and Permutation(分块区间查询,动态查询[l,r]内小于某个值的元素个数)
- Codeforces Round #404 (Div. 2) E. Anton and Permutation(分块+二分)
- E. Anton and Permutation (树状数组+主席树)
- CodeForces 734 E.Anton and Tree(dfs)
- Codeforces-734E Anton and Tree(树的直径)
- Codeforces 584E Anton and Ira
- CodeForces 584E Anton and Ira
- 【25.00%】【codeforces 584E】Anton and Ira
- CodeForces 734E - Anton and Tree
- 浅谈自定义View之自定义布局FlowLayout
- Java垃圾回收学习笔记
- JAVA POI导入技术之EXCEL模板中制作下拉列表
- 运算符重载的实现代码
- MySQL中的存储引擎讲解(InnoDB,MyISAM,Memory等各存储引擎对比)
- codeforces 785 E. Anton and Permutation(分块)
- 使用Python实现每日一句英语发送到手机
- eclispe使用maven创建web项目后更改java和web版本
- Loop指令
- React学习之列表运用(七)
- java并发包-ReentrantLock(三):如何解锁
- Tensorflow一些常用基本概念与函数4
- 51 nod 1405 树的距离之和 详细题解(树形DP)
- ACM程序设计书中题目--z(两组字符串中单词的首字母是否相同)