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 ...
随机推荐
- ASP.NET MVC4中加入Log4Net日志记录功能
前言 在之前的.NET中,微软还没有提供过像样的日志框架,目前能用的一些框架比如Log4Net.NLog.CommonLogging等,虽然多多少少使用起来有点费劲,但这里还是简单分享一下Log4Ne ...
- 擠出機步進馬達的 Steps per Unit 該如何計算?
擠出機步進馬達的 Steps per Unit 該如何計算? 這邊 Steps per Unit 指的是塑料往前推進1mm,步進馬達須要走幾步.依此定義,可知計算方式可以用 步進馬達轉一圈需要的步 ...
- BR(BoomerangRobot)机器人项目
项目宗旨:推动机器人技术及相关知识的普及,增进广大机器人DIYer们的交流,提高爱好者们自身的专业水平,项目提供以机器人BR(boomerangrobot)为硬件平台,ROS(robot operat ...
- Codeforces Round #319 (Div. 2) D
E A tree of size n is an undirected connected graph consisting of n vertices without cycles. Conside ...
- MySql获取两个日期间的时间差
[1]MySql 语言获取两个日期间的时间差 DATEDIFF 函数可以获得两个日期之间的时间差.但是,这个函数得出的结果是天数. 需要直接获取秒数可使用TIMESTAMPDIFF函数.应用示例如下: ...
- 机器学习-LR推导及与SVM的区别
之前整理过一篇关于逻辑回归的帖子,但是只是简单介绍了一下了LR的基本思想,面试的时候基本用不上,那么这篇帖子就深入理解一下LR的一些知识,希望能够对面试有一定的帮助. 1.逻辑斯谛分布 介绍逻辑斯谛回 ...
- linux常用命令:ls命令
ls命令是linux下最常用的命令.ls命令就是list的缩写,缺省下ls用来打印出当前目录的清单,如果ls指定其他目录那么就会显示指定目录里的文件及文件夹清单. 通过ls 命令不仅可以查看linux ...
- nodejs之pm2自动重启服务
pm2 start xxx #启动服务器 pm2 list #查看运行状态 pm2 logs #查看日志 pm2 restart xxx #重启应用 pm2 stop xxx #停止应用 监听修改,并 ...
- go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE
go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE Go语言是谷歌2009发布的专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速 ...
- 自学Java第三个星期的总结
在这一周里我在网上学习了java的分支结构.Number&Matht类.Character类.string类.String Buffer和String Builder类以及数组和日期时间等有关 ...