luogu1975 [国家集训队]排队
思路
序列中
| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| a[i] | a | b | c | L | d | e | f | R | g | h |
现逆序对为ans,要交换L,R
则\([1,3],[9,10]\)这两段区间的都不会被他俩影响 (因为L,R和他们相对位置没变啦)
所以现在我们只需要考虑区间\([4,8]\)就好,其他的不考虑在内
一个数对一个区间产生逆序对的贡献为
① 前面大于他的数的个数 (在区间前面)
② 后面小于他的数的个数 (在区间后面)
因为\(L,R\)之间的区间3,6是不变的(废话)
\(L,R\)又在区间两端
那么很显然的
\(ans=ans-(L对区间zz的贡献②)+(L对区间zz的贡献①)-(R对区间zz的贡献①)+(R对区间zz的贡献②)\)
那区间内的贡献咋求啊?
定义不是很明确了吗 就是区间大于x或者小于的个数
\(=>ans-(区间zz内小于L的个数)+(区间zz内大于L的个数)-(区间zz内大于R的个数)+(区间zz内小于R的个数)\)(注意,相等的没有任何贡献)
无脑数据结构呗
随便来个带修主席树 (树状数组套线段树)
复杂度\(nlog^{2}n\)
但常数巨大,更新一次ans要询问8次
错误
都是些zz错误
n写成len
特盘忘记输出ans
代码
//天苍苍,野茫茫,代码怎么这么长
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,ans,len,rt[maxn],a[maxn],lsh[maxn],cnt;
int thu[maxn];
struct node {
int ch[2],siz;
}e[maxn*30];
void build(int &now,int old,int l,int r,int k) {
now=++cnt;
e[now]=e[old];
e[now].siz++;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) build(e[now].ch[0],e[old].ch[0],l,mid,k);
else build(e[now].ch[1],e[old].ch[1],mid+1,r,k);
}
void modify(int &now,int l,int r,int k,int gs) {
if(!now) now=++cnt;
e[now].siz+=gs;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) modify(e[now].ch[0],l,mid,k,gs);
else modify(e[now].ch[1],mid+1,r,k,gs);
}
int query1(int now,int l,int r,int k) { //小于mid的数
if(l>=k) return 0;
if(r<k) {
int tot=e[now].siz;
FOR(i,1,thu[0]) tot+=e[thu[i]].siz;
return tot;
}
int mid=(l+r)>>1;
if(k<=mid) {
FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[0];
return query1(e[now].ch[0],l,mid,k);
} else {
int tot=e[e[now].ch[0]].siz;
FOR(i,1,thu[0]) tot+=e[e[thu[i]].ch[0]].siz;
FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[1];
return tot+query1(e[now].ch[1],mid+1,r,k);
}
}
int query2(int now,int l,int r,int k) { //大于mid的数
if(r<=k) return 0;
if(l>k) {
int tot=e[now].siz;
FOR(i,1,thu[0]) tot+=e[thu[i]].siz;
return tot;
}
int mid=(l+r)>>1;
if(k<=mid) {
int tot=e[e[now].ch[1]].siz;
FOR(i,1,thu[0]) tot+=e[e[thu[i]].ch[1]].siz;
FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[0];
return tot+query2(e[now].ch[0],l,mid,k);
} else {
FOR(i,1,thu[0]) thu[i]=e[thu[i]].ch[1];
return query2(e[now].ch[1],mid+1,r,k);
}
}
int solve(int l,int r,int k,int pd) {//区间内小于(或小于)k的个数
int tmp=0;
thu[0]=0;
for(int i=r;i>=1;i-=(i&-i)) thu[++thu[0]]=rt[i+n];
tmp+=pd ? query1(rt[r],1,len,k) : query2(rt[r],1,len,k);
thu[0]=0;
for(int i=l-1;i>=1;i-=(i&-i)) thu[++thu[0]]=rt[i+n];
tmp-=pd ? query1(rt[l-1],1,len,k) : query2(rt[l-1],1,len,k);
return tmp;
}
namespace get_init_ans {
int sum[maxn];
void BIT_modify(int x) {
for(int i=x;i<=n;i+=(i&-i)) sum[i]++;
}
int BIT_query(int x) {
int tot=0;
for(int i=x;i>=1;i-=(i&-i)) tot+=sum[i];
return tot;
}
void get_ans() {
for(int i=1;i<=n;++i) {
BIT_modify(a[i]);
ans+=i-BIT_query(a[i]);
}
}
}
using namespace get_init_ans;
int main() {
//read
n=read();
FOR(i,1,n) a[i]=lsh[i]=read();
//lsh and init
sort(lsh+1,lsh+1+n);
len=unique(lsh+1,lsh+1+n)-lsh-1;
FOR(i,1,n) {
a[i]=lower_bound(lsh+1,lsh+1+len,a[i])-lsh;
build(rt[i],rt[i-1],1,len,a[i]);
}
//get_ans
get_ans();
cout<<ans<<"\n";
//work
m=read();
FOR(i_ak_ioi,1,m) {
int x=read(),y=read(),l,l1=0,l2=0,r,r1=0,r2=0;
if(a[x]==a[y]) {
cout<<ans<<"\n";
continue;
}
if(x>y) swap(x,y);
//query
l=x+1,r=y-1;
if(l<=r) {
l2=solve(l,r,a[x],1);
l1=solve(l,r,a[x],0);
r2=solve(l,r,a[y],1);
r1=solve(l,r,a[y],0);
}
//update
ans=ans-l2+l1-r1+r2+(a[x]<a[y] ? 1 : -1);
cout<<ans<<"\n";
//update
for(int i=x;i<=n;i+=(i&-i)) {
modify(rt[i+n],1,len,a[x],-1);
modify(rt[i+n],1,len,a[y],1);
}
for(int i=y;i<=n;i+=(i&-i)) {
modify(rt[i+n],1,len,a[y],-1);
modify(rt[i+n],1,len,a[x],1);
}
swap(a[x],a[y]);
}
return 0;
}
luogu1975 [国家集训队]排队的更多相关文章
- Luogu-1975 [国家集训队]排队
Luogu-1975 [国家集训队]排队 题面 Luogu-1975 题解 题意:给出一个长度为n的数列以及m个交换两个数的操作,问每次操作后逆序对数量 时间,下标和数的大小三维偏序,,,把交换操作看 ...
- 【LG1975】[国家集训队]排队
[LG1975][国家集训队]排队 题面 洛谷 题解 又是一个偏序问题 显然\(CDQ\) 交换操作不好弄怎么办? 可以看成两次删除两次插入 排序问题要注意一下 代码 #include <ios ...
- [国家集训队]排队 [cdq分治]
题面 洛谷 和动态逆序对那道题没有什么区别 把一个交换换成两个删除和两个插入 #include <cstdio> #include <cstdlib> #include < ...
- P1975 [国家集训队]排队
题目链接 题意分析 我们考虑 交换两个数\([le,ri]\)的贡献 减少的逆序对数\([le,ri]\)中小于\(num[le]\)以及大于\(num[ri]\)的数 增加的\([le,ri]\)中 ...
- P1975 [国家集训队]排队 线段树套平衡树维护动态逆序对查询
$ \color{#0066ff}{ 题目描述 }$ 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和. 红星幼儿园的小朋友们排起了长长地队伍 ...
- 洛谷 P1975 [国家集训队]排队 Lebal:块内排序+树状数组
题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和. 红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...
- [luoguP1975] [国家集训队]排队(分块)
传送门 直接暴力分块,然后在每一个块内排序. 查询时可以在每一个块内二分. #include <cmath> #include <cstdio> #include <io ...
- 「Luogu P1975 [国家集训队]排队」
题目大意 给出一个序列 \(h\),支持交换其中的两数,求出每一时刻的逆序对个数. 分析 求逆序对是 \(O(N\log_2N)\) 的,有 \(M\) 个操作,如果暴力求的话时间复杂度就是 \(O( ...
- BZOJ 2039: [2009国家集训队]employ人员雇佣
2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 1369 Solved: 667[Submit ...
随机推荐
- activity bj draw 流程图
- word中加入endnote
http://jingyan.baidu.com/article/f54ae2fc3926d91e92b849c2.html 1.如果安装完endnote后,word中没有出现 endnote菜单,则 ...
- 《大话设计模式》c++实现 抽象工厂模式
为了更清晰地理解工厂方法模式,需要先引入两个概念: 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机.海信电视机.TCL电视机,则抽象电视机与具体品牌的电视机之间 ...
- Problem(莫比乌斯反演)
我不是传送门 题意 : 中文题目不解释 求gcd(x,y) = k (a<=x<=b, c<=y<=d); 根据gcd(ka,kb) = k*gcd(a,b), 可将问题转化为 ...
- Ngine X 完全开发指南 读书笔记-前言
一开始接触的编程语言是VF,那是一种可视化编程语言,所谓的可视化,就是运行结果能直接看得到的,非常直观,便于调试,适合刚刚接触编程的新人学习.当时学得懵懂,半知半解,就是感觉程序非常神奇,常常几句代码 ...
- Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器
一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...
- mac下编译cpu only caffe并用xCode建caffe工程
mac编译caffe 好像又变容易了,直接git clone下载blvc源码,make.config里去掉了CPU_ONLY前面的注释,并没有安装任何依赖,也可能是自己mac上本来有, xCode里调 ...
- python练习题-打印斐波拉契数列前n项
打印斐波拉契数列前n项 #encoding=utf-8 def fibs(num): result =[0,1] for i in range(num-2): result. ...
- docker Dockerfile指令ADD和COPY的区别,添加目录方法
docker Dockerfile指令ADD和COPY的区别,添加目录方法 ADD指令的功能是将主机构建环境(上下文)目录中的文件和目录.以及一个URL标记的文件 拷贝到镜像中.其格式是: ADD 源 ...
- python--表达式(运算表达式)
运算表达式 python 的表达式包括:算术运算符,赋值运算符,比较运算符,成员运算符 算术运算符 运算符 描述 + 加 - 两个对象相加 - 减 - 得到负数或是一个数减去另一个数 * 乘 - 两个 ...