题目描述

排排坐,吃果果,生果甜嗦嗦,大家笑呵呵。你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家
乐和和。红星幼儿园的小朋友们排起了长长地队伍,准备吃果果。不过因为小朋友们的身高有所区别,排成的队伍
高低错乱,极不美观。设第i个小朋友的身高为hi,我们定义一个序列的杂乱程度为:满足ihj的(i,j)数量。幼儿
园阿姨每次会选出两个小朋友,交换他们的位置,请你帮忙计算出每次交换后,序列的杂乱程度。为方便幼儿园阿
姨统计,在未进行任何交换操作时,你也应该输出该序列的杂乱程度。

输入

第一行为一个正整数n,表示小朋友的数量;
第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高;
第三行为一个正整数m,表示交换操作的次数;
以下m行每行包含两个正整数ai和bi,表示交换位置ai与位置bi的小朋友。
1≤m≤2*10^3,1≤n≤2*104,1≤hi≤109,ai≠bi,1≤ai,bi≤n。

输出

输出文件共m行,第i行一个正整数表示交换操作i结束后,序列的杂乱程度。

样例输入

【样例输入】
3
130 150 140
2
2 3
1 3

样例输出

1
0
3
【样例说明】
未进行任何操作时,(2,3)满足条件;
操作1结束后,序列为130 140 150,不存在满足i<j且hi>hj的(i,j)对;
操作2结束后,序列为150 140 130,(1,2),(1,3),(2,3)共3对满足条件的(i,j)
 
  题目大意是求每次交换两个数后的逆序对数。最开始没修改时直接用树状数组求逆序对数就好了。因为逆序对数就是考虑每个数后面比它小的数有多少个,所以每次交换两个数i,j对这两个数与j后面的数产生的逆序对数没有影响,只对i,j中间的数与两个数产生的逆序对数有影响。考虑i,交换之后,i与i,j之间比i小的数产生的逆序对数消失了,但多了i,j之间比i大的数与i的逆序对数,j也是同样道理。所以只要每次求i,j之间比i或j小的和大的数有多少,用主席树维护就好了,但因为每次交换时会修改,因此要用树状数组套权值线段树,也就是带修改的主席树。最后要注意i,j两个数产生的逆序对数的增减。
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int n,m;
int x,y;
int tot;
int cnt;
int ans;
int s[20010];
int t[20010];
int a[20010];
int b[20010];
int v[20010];
int root[20010];
int ls[10000010];
int rs[10000010];
int sum[10000010];
void add(int x)
{
for(int i=x;i<=tot;i+=i&-i)
{
v[i]++;
}
}
int ask(int x)
{
int res=0;
for(int i=x;i;i-=i&-i)
{
res+=v[i];
}
return res;
}
void change(int &rt,int l,int r,int k,int v)
{
if(!rt)
{
rt=++cnt;
}
if(l==r)
{
sum[rt]+=v;
return ;
}
sum[rt]+=v;
int mid=(l+r)>>1;
if(k<=mid)
{
change(ls[rt],l,mid,k,v);
}
else
{
change(rs[rt],mid+1,r,k,v);
}
}
int query_min(int l,int r,int k)
{
int res=0;
if(l==r)
{
return res;
}
int mid=(l+r)>>1;
if(k<=mid)
{
for(int i=1;i<=s[0];i++)
{
s[i]=ls[s[i]];
}
for(int i=1;i<=t[0];i++)
{
t[i]=ls[t[i]];
}
return query_min(l,mid,k);
}
else
{
for(int i=1;i<=s[0];i++)
{
res+=sum[ls[s[i]]];
s[i]=rs[s[i]];
}
for(int i=1;i<=t[0];i++)
{
res-=sum[ls[t[i]]];
t[i]=rs[t[i]];
}
return res+query_min(mid+1,r,k);
}
}
int query_max(int l,int r,int k)
{
int res=0;
if(l==r)
{
return res;
}
int mid=(l+r)>>1;
if(k<=mid)
{
for(int i=1;i<=s[0];i++)
{
res+=sum[rs[s[i]]];
s[i]=ls[s[i]];
}
for(int i=1;i<=t[0];i++)
{
res-=sum[rs[t[i]]];
t[i]=ls[t[i]];
}
return res+query_max(l,mid,k);
}
else
{
for(int i=1;i<=s[0];i++)
{
s[i]=rs[s[i]];
}
for(int i=1;i<=t[0];i++)
{
t[i]=rs[t[i]];
}
return query_max(mid+1,r,k);
}
}
void updata(int x,int k,int v)
{
for(int i=x;i<=n;i+=i&-i)
{
change(root[i],1,tot,k,v);
}
}
int find_max(int l,int r,int k)
{
s[0]=t[0]=0;
for(int i=r;i;i-=i&-i)
{
s[++s[0]]=root[i];
}
for(int i=l;i;i-=i&-i)
{
t[++t[0]]=root[i];
}
return query_max(1,tot,k);
}
int find_min(int l,int r,int k)
{
s[0]=t[0]=0;
for(int i=r;i;i-=i&-i)
{
s[++s[0]]=root[i];
}
for(int i=l;i;i-=i&-i)
{
t[++t[0]]=root[i];
}
return query_min(1,tot,k);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
tot=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
ans+=ask(tot)-ask(a[i]);
add(a[i]);
updata(i,a[i],1);
}
printf("%d\n",ans);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
ans+=find_min(x,y-1,a[y]);
ans-=find_max(x,y-1,a[y]);
ans-=find_min(x,y-1,a[x]);
ans+=find_max(x,y-1,a[x]);
updata(x,a[x],-1);
updata(y,a[y],-1);
swap(a[x],a[y]);
updata(x,a[x],1);
updata(y,a[y],1);
if(a[x]>a[y])
{
ans++;
}
else if(a[x]<a[y])
{
ans--;
}
printf("%d\n",ans);
}
}

BZOJ2141排队——树状数组套权值线段树(带修改的主席树)的更多相关文章

  1. luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)

    带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...

  2. CF1093E Intersection of Permutations 树状数组套权值线段树

    \(\color{#0066ff}{ 题目描述 }\) 给定整数 \(n\) 和两个 \(1,\dots,n\) 的排列 \(a,b\). \(m\) 个操作,操作有两种: \(1\ l_a\ r_a ...

  3. Dynamic Rankings(树状数组套权值线段树)

    Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...

  4. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  5. 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings

    谁再管这玩意叫树状数组套主席树我跟谁急 明明就是树状数组的每个结点维护一棵动态开结点的权值线段树而已 好吧,其实只有一个指针,指向该结点的权值线段树的当前结点 每次查询之前,要让指针指向根结点 不同结 ...

  6. 刷题总结——骑士的旅行(bzoj4336 树链剖分套权值线段树)

    题目: Description 在一片古老的土地上,有一个繁荣的文明. 这片大地几乎被森林覆盖,有N座城坐落其中.巧合的是,这N座城由恰好N-1条双 向道路连接起来,使得任意两座城都是连通的.也就是说 ...

  7. BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树

    题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条 ...

  8. BZOJ 2120 数颜色(树状数组套主席树)

    1A啊,激动. 首先,不修改的情况下可以直接用主席树搞,修改的话,直接用主席树搞一次修改的情况下复杂度是O(nlogn)的. 就像你要求区间和一样,用前缀和查询是O(1),修改是O(n),只不过主席树 ...

  9. LUOGU P2617 Dynamic Rankings(树状数组套主席树)

    传送门 解题思路 动态区间第\(k\)大,树状数组套主席树模板.树状数组的每个位置的意思的是每棵主席树的根,维护的是一个前缀和.然后询问的时候\(log\)个点一起做前缀和,一起移动.时空复杂度\(O ...

随机推荐

  1. Android学习之基础知识十四 — Android特色开发之基于位置的服务

    一.基于位置的服务简介 LBS:基于位置的服务.随着移动互联网的兴起,这个技术在最近的几年里十分火爆.其实它本身并不是什么时髦的技术,主要的工作原理就是利用无线电通讯网络或GPS等定位方式来确定出移动 ...

  2. Android对接微信支付体验

    在写正文之前我不得不吐槽一下:微信支付所提供的参考文档以及技术支持真心太烂了. 微信的坑: 1.在生成prepay_id向微信服务器传递参数时<body>不支持中文.需要对其进行转码,否则 ...

  3. 洛谷 P1525 关押罪犯

    题目链接 https://www.luogu.org/problemnew/show/P1525 题目描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1−N.他们之间的关系自然也极不和谐.很多罪 ...

  4. STL语法——集合:set 安迪的第一个字典(Andy's First Dictionary,UVa 10815)

    Description Andy, , has a dream - he wants to produce his very own dictionary. This is not an easy t ...

  5. wifidog源码分析 - wifidog原理

    wifidog是一个用于配合认证服务器实现无线网页认证功能的程序,常见的情景就是使用于公共场合的无线wifi接入点,首先移动设备会连接公共wifi接入点,之后会弹出网页要求输入用户名密码,认证过后才能 ...

  6. Python写代码的时候为什么要注释?Sun因此被Oracle收购

    导读: 此块分为:1.注释的重要性 2.如何正确注释 注释的重要性 在我们看代码的时候,会遇到很多看不懂得代码,特别是在做项目的时候,代码的注释以及命名习惯的重要性就有了为什么这么说呢? 因为在很多情 ...

  7. CF293B Distinct Paths 搜索

    传送门 首先数据范围很假 当\(N + M - 1 > K\)的时候就无解 所以对于所有要计算的情况,\(N + M \leq 11\) 超级小是吧,考虑搜索 对于每一个格子试填一个数 对于任意 ...

  8. 数据库日志——mysql与Oracle的日志

    一.MySQL 在数据同步中用的比较多的是MySQL的binlog 1.bin-log简介 它记录了所有的DDL和DML(除了数据查询语句,select与show不记录)语句,以事件形式记录,还包含语 ...

  9. PCB之PASTE助焊层和SOLDER阻焊层

    1.PASTE为焊接层,用于SMT贴片元件的焊接,对应的图形为钢网(钢网上的小孔): 2.SOLDER为阻焊层,它代表的是绿油的涂抹区域,且为负片输出(负片输出指的是图形以外的区域为有效区域): PA ...

  10. JVM规范系列第1章:引言

    如果你还没下载<Java虚拟机规范>这本书,那么先点击这里下载再一块儿看吧. 前言 Java 虚拟机是一个抽象化的机器,整个规范中提及的 Java 虚拟机都是抽象化的概念,而不是特指 Or ...