洛谷 P1393 P3157 动态逆序对
嘛,好久没碰CDQ分治了,做道题练练手。
时间倒流——把删数改为加数。
对于每个被删的,我的想法是拆成询问和add,后来发现一个足矣。
我本来准备对每个删的数都求一遍整体逆序对,后来发现无论如何都不可做。
然后发现是只求改的逆序对,做两次CDQ,一次统计在前面大的,一次统计在后面小的。
注意:这两次的区别是id那一维的顺序不同,而time顺序是相同的。
记得离散化。
然后我打完 + 静态差错之后,一发过样例AC,稳!!!
顺手切了一模一样的3157,WA了两个点。发现输出负数......换成longlong之后AC。
#include <cstdio>
#include <algorithm>
#include <cstring> typedef long long LL; const LL N = ; LL x[N], a[N], n; struct TreeArray {
LL tr[N];
inline void clear() {
memset(tr, , sizeof(tr));
return;
}
inline void add(LL x, LL a) {
for(; x < N; x += x & (-x)) {
tr[x] += a;
}
return;
}
inline LL getsum(LL x) {
LL ans = ;
for(; x; x -= x & (-x)) {
ans += tr[x];
}
return ans;
}
inline LL ask(LL l, LL r) {
if(l == ) {
return getsum(r);
}
return getsum(r) - getsum(l - );
}
}ta; struct Node {
LL val, ans, time, type, id;
}node[N], temp[N]; inline bool cmp_t(Node d, Node e) {
return d.time < e.time;
}
inline bool cmp__t(Node d, Node e) {
return d.time > e.time;
} void CDQ1(LL l, LL r) {
if(l == r) {
return;
}
LL mid = (l + r) >> ;
CDQ1(l, mid);
CDQ1(mid + , r); LL i = l, j = mid + , t = ;
while(i <= mid || j <= r) {
if(j > r || (i <= mid && node[i].id < node[j].id)) {
ta.add(node[i].val, );
temp[++t] = node[i++];
}
else {
if(node[j].type == ) {
node[j].ans += ta.ask(node[j].val + , n);
}
temp[++t] = node[j++];
}
}
for(i = l; i <= mid; i++) {
ta.add(node[i].val, -);
}
t = ;
for(LL i = l; i <= r; i++) {
node[i] = temp[++t];
}
return;
} void CDQ2(LL l, LL r) {
if(l == r) {
return;
}
LL mid = (l + r) >> ;
CDQ2(l, mid);
CDQ2(mid + , r); LL i = l, j = mid + , t = ;
while(i <= mid || j <= r) {
if(j > r || (i <= mid && node[i].id > node[j].id)) { /// error : id < id
ta.add(node[i].val, 1);/// error : if(type == 1)
temp[++t] = node[i++];
}
else {
if(node[j].type == ) {
node[j].ans += ta.getsum(node[j].val - );
}
temp[++t] = node[j++];
}
}
for(i = l; i <= mid; i++) {
ta.add(node[i].val, -);/// error : if(type == 1)
}
t = ;
for(i = l; i <= r; i++) {
node[i] = temp[++t];
}
return;
} LL pos[N]; int main() {
LL m;
scanf("%lld%lld", &n, &m);
for(LL i = ; i <= n; i++) {
scanf("%lld", &a[i]);
x[i] = a[i];
node[i].id = i;
node[i].type = ; /// normal
}
std::sort(x + , x + n + );
LL xx = std::unique(x + , x + n + ) - x - ;
for(LL i = ; i <= n; i++) {
LL p = std::lower_bound(x + , x + xx + , a[i]) - x;
node[i].val = p;
pos[p] = i;
}
/// li san hua wan bi LL nn = n, p;
for(LL i = ; i <= m; i++) {
scanf("%lld", &p);
p = std::lower_bound(x + , x + xx + , p) - x;
p = pos[p];
node[p].type = ; /// add
node[p].time = nn--;
}
for(LL i = ; i <= n; i++) {
if(node[i].type == ) {
node[i].time = nn--;
}
}
LL ans = ;
for(LL i = ; i <= n; i++) {
if(node[i].type == ) {
ans += ta.ask(node[i].val + , n);
ta.add(node[i].val, );
}
}
ta.clear();
std::sort(node + , node + n + , cmp_t);
CDQ1(, n);
std::sort(node + , node + n + , cmp_t); /// error : cmp__t -> cmp_t
CDQ2(, n);
std::sort(node + , node + n + , cmp__t);
for(LL i = ; i <= m; i++) {
ans += node[i].ans;
}
for(LL i = ; i <= m; i++) {
printf("%lld\n", ans);
ans -= node[i].ans;
}
return ;
}
P3157
#include <cstdio>
#include <algorithm>
#include <cstring> const int N = ; int x[N], a[N], n; struct TreeArray {
int tr[N];
inline void clear() {
memset(tr, , sizeof(tr));
return;
}
inline void add(int x, int a) {
for(; x < N; x += x & (-x)) {
tr[x] += a;
}
return;
}
inline int getsum(int x) {
int ans = ;
for(; x; x -= x & (-x)) {
ans += tr[x];
}
return ans;
}
inline int ask(int l, int r) {
if(l == ) {
return getsum(r);
}
return getsum(r) - getsum(l - );
}
}ta; struct Node {
int val, ans, time, type, id;
}node[N], temp[N]; inline bool cmp_t(Node d, Node e) {
return d.time < e.time;
}
inline bool cmp__t(Node d, Node e) {
return d.time > e.time;
} void CDQ1(int l, int r) {
if(l == r) {
return;
}
int mid = (l + r) >> ;
CDQ1(l, mid);
CDQ1(mid + , r); int i = l, j = mid + , t = ;
while(i <= mid || j <= r) {
if(j > r || (i <= mid && node[i].id < node[j].id)) {
ta.add(node[i].val, );
temp[++t] = node[i++];
}
else {
if(node[j].type == ) {
node[j].ans += ta.ask(node[j].val + , n);
}
temp[++t] = node[j++];
}
}
for(i = l; i <= mid; i++) {
ta.add(node[i].val, -);
}
t = ;
for(int i = l; i <= r; i++) {
node[i] = temp[++t];
}
return;
} void CDQ2(int l, int r) {
if(l == r) {
return;
}
int mid = (l + r) >> ;
CDQ2(l, mid);
CDQ2(mid + , r); int i = l, j = mid + , t = ;
while(i <= mid || j <= r) {
if(j > r || (i <= mid && node[i].id > node[j].id)) {
ta.add(node[i].val, );
temp[++t] = node[i++];
}
else {
if(node[j].type == ) {
node[j].ans += ta.getsum(node[j].val - );
}
temp[++t] = node[j++];
}
}
for(i = l; i <= mid; i++) {
ta.add(node[i].val, -);
}
t = ;
for(i = l; i <= r; i++) {
node[i] = temp[++t];
}
return;
} int main() {
int m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
x[i] = a[i];
node[i].id = i;
node[i].type = ; /// normal
}
std::sort(x + , x + n + );
int xx = std::unique(x + , x + n + ) - x - ;
for(int i = ; i <= n; i++) {
int p = std::lower_bound(x + , x + xx + , a[i]) - x;
node[i].val = p;
}
/// li san hua wan bi int nn = n;
for(int i = ; i <= m; i++) {
scanf("%d", &xx);
node[xx].type = ; /// add
node[xx].time = nn--;
}
for(int i = ; i <= n; i++) {
if(node[i].type == ) {
node[i].time = nn--;
}
}
int ans = ;
for(int i = ; i <= n; i++) {
if(node[i].type == ) {
ans += ta.ask(node[i].val + , n);
ta.add(node[i].val, );
}
}
ta.clear();
std::sort(node + , node + n + , cmp_t);
CDQ1(, n);
std::sort(node + , node + n + , cmp_t);
CDQ2(, n);
std::sort(node + , node + n + , cmp__t);
for(int i = ; i <= m; i++) {
ans += node[i].ans;
}
for(int i = ; i <= m + ; i++) {
printf("%d ", ans);
ans -= node[i].ans;
}
return ;
}
P1393
CDQ大法好!
洛谷 P1393 P3157 动态逆序对的更多相关文章
- P3157 动态逆序对 CDQ分治
动态逆序对 CDQ分治 传送门:https://www.luogu.org/problemnew/show/P3157 题意: 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对 ...
- 洛谷P3157 动态逆序对 [CQOI2011] cdq分治
正解:cdq分治 解题报告: 传送门! 长得有点像双倍经验还麻油仔细看先放上来QwQ! 这题首先想到的就直接做逆序对,然后记录每个点的贡献,删去就减掉就好 但是仔细一想会发现布星啊,如果有一对逆序对的 ...
- 【洛谷 P2513】 [HAOI2009]逆序对数列(DP)
题目链接 这种求方案数的题一般都是\(dp\)吧. 注意到范围里\(k\)和\(n\)的范围一样大,\(k\)是完全可以更大的,到\(n\)的平方级别,所以这暗示了我们要把\(k\)写到状态里. \( ...
- 洛谷 P4280 bzoj1786 [AHOI2008]逆序对(dp)
题面 luogu bzoj 题目大意: 给你一个长度为\(n\)的序列,元素都在\(1-k\)之间,有些是\(-1\),让你把\(-1\)也变成\(1-k\)之间的数,使得逆序对最多,求逆序对最少是多 ...
- 洛谷P1966 火柴排队(逆序对)
题意 题目链接 Sol 不算很难的一道题 首先要保证权值最小,不难想到一种贪心策略,即把两个序列中rank相同的数放到同一个位置 证明也比较trivial.假设\(A\)中有两个元素\(a, b\), ...
- 洛谷【P1908】逆序对
题目传送门:https://www.luogu.org/problemnew/show/P1908 所谓逆序对,就是序列中\(a[i]>a[j]\)且\(i<j\)的有序对. 所以我们在归 ...
- 【Luogu】P3157动态逆序对(树状数组套主席树)
题目链接 md第一道在NOILinux 下用vim做的紫题.由于我对这个操作系统不是很熟悉,似乎有什么地方搞错了,md调死.(我还打了两遍代码,调了两个小时) 但是这道题并不难,就是树状数组套上主席树 ...
- 洛谷 题解 P1908 【逆序对】
一开始竟然妄想用\(n^2\)的算法过这题,然而这是不可能的 所以只好写归并排序来求逆序対惹 比如将下面两个区间排序 3 4 7 9 1 5 8 10 首先将右区间的\(1\)取出,放到\(r_k\) ...
- bzoj3295 洛谷P3157、1393 动态逆序对——树套树
题目:bzoj3295 https://www.lydsy.com/JudgeOnline/problem.php?id=3295 洛谷 P3157(同一道题) https://www.luogu.o ...
随机推荐
- java学习之—链表(3)
/** * 使用链表实现队列 * Create by Administrator * 2018/6/19 0019 * 下午 4:37 **/ public class Link { public l ...
- 从Oracle数据库中查询前几个月数据时需要注意的一些问题
在最近的一个项目中,有一个需求就是要查询数据库中前几个月的历史数据,但是由于自己考虑不全面造成了程序的bug,现在将这一块好好作一个总结,希望以后不再犯这种很低级的错误,首先贴出查询中用到的一个子函数 ...
- 原 线程池中shutdown()和shutdownNow()方法的区别
参考:shutdown和shutdownNow的区别 shutDown() 当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态.此时,则不能再往线程池中添加任何任务,否则将会抛出Reje ...
- WEX5中ajax跨域访问的几种方式
1.使用jsonp方式 使用jsonp访问的话,前端需要把回调函数名传递给后端,后端执行完后也需要把回调函数传回给前端,默认情况下ajax自动生成一个回调函数名,后端可以通过String callba ...
- 老男孩python学习自修第十九天【异常处理】
1.常见的错误 TypeError 类型错误 NameError 没有该变量 ValueError 不期望的值 AttributeError 没有该属性 UnboundLocalError 没有该局部 ...
- Hibernate **关于hibernate4.3版本之后org.hibernate.service.ServiceRegistryBuilder被弃用**
之前一直都是使用hibernate4.2.21的我,有一天突然没有使用本地的jar包而是让IDEA自动下载最新版本的hibernate5.2.2之后,发现有几个经常使用的方法报错了. //创建配置对象 ...
- 常用css样式处理
1:如何设置html的input框的高度和宽度! 用style来设置,<input style="width:111px;height:111px">
- Vue-router的API详解
前面的话 本文将详细介绍Vue-router的API router-link <router-link> 组件支持用户在具有路由功能的应用中点击导航. 通过 to 属性指定目标地址,默认渲 ...
- Web API2 使用默认Identity
当您选择个人账户在Web API项目模板,项目包含一个令牌授权服务器验证用户凭证和问题.下面的图显示了相同的凭证流的Web API组件. 发送一个未经授权的请求 首先,运行应用程序并单击按钮调用的AP ...
- socket跟TCP/IP 的关系,单台服务器上的并发TCP连接数可以有多少
常识一:文件句柄限制 在Linux下编写网络服务器程序的朋友肯定都知道每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,新的连接到来返回给我们的错误是"Socket/File ...