【bzoj3295】[Cqoi2011]动态逆序对 线段树套SBT
题目描述
输入
输出
样例输入
5 4
1
5
3
4
2
5
1
4
2
样例输出
5
2
2
1
题解
个人不喜欢CDQ分治,所以写了个线段树套SBT
想法很自然,删除某个数,减少的贡献为它左边比它大的数的个数+它右边比它小的数的个数。外层维护区间线段树,内层维护平衡树(不用权值线段树因为卡空间),查找时找到对应区间在平衡树中查询;删除时把外层从根到对应叶子的每个节点在平衡树中删除掉。
然而写到一半CQzhangyu告诉我本题卡树套树,看了下Discuss发现还真是 = =。
于是赶紧把Treap换成SBT,然而还是TLE。
没办法,再把数组版改成结构体版,最终AC。
然而跑得还是比CDQ分治慢了5倍左右= =
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N 100010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
struct data
{
int l , r , w , si;
}a[N << 5];
int pos[N] , v[N] , root[N << 2] , tot;
inline int read()
{
int ret = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') ret = (ret << 3) + (ret << 1) + ch - '0' , ch = getchar();
return ret;
}
void zig(int &k)
{
int t = a[k].l;
a[k].l = a[t].r , a[t].r = k , a[t].si = a[k].si , a[k].si = a[a[k].l].si + a[a[k].r].si + 1;
k = t;
}
void zag(int &k)
{
int t = a[k].r;
a[k].r = a[t].l , a[t].l = k , a[t].si = a[k].si , a[k].si = a[a[k].l].si + a[a[k].r].si + 1;
k = t;
}
void maintain(int &k , bool flag)
{
if(!flag)
{
if(a[a[a[k].l].l].si > a[a[k].r].si) zig(k);
else if(a[a[a[k].l].r].si > a[a[k].r].si) zag(a[k].l) , zig(k);
else return;
}
else
{
if(a[a[a[k].r].r].si > a[a[k].l].si) zag(k);
else if(a[a[a[k].r].l].si > a[a[k].l].si) zig(a[k].r) , zag(k);
else return;
}
maintain(a[k].l , false) , maintain(a[k].r , true);
maintain(k , false) , maintain(k , true);
}
void add(int &k , int x)
{
if(!k) k = ++tot , a[k].w = x , a[k].si = 1;
else
{
a[k].si ++ ;
if(x < a[k].w) add(a[k].l , x);
else add(a[k].r , x);
maintain(k , x >= a[k].w);
}
}
void del(int &k , int x)
{
a[k].si -- ;
if(x < a[k].w) del(a[k].l , x);
else if(x > a[k].w) del(a[k].r , x);
else
{
if(!a[k].l || !a[k].r) k = a[k].l + a[k].r;
else
{
int t = a[k].r , last = k;
while(a[t].l) a[t].si -- , last = t , t = a[t].l;
if(t == a[last].l) a[last].l = a[t].r;
else a[last].r = a[t].r;
a[t].l = a[k].l , a[t].r = a[k].r , a[t].si = a[k].si , k = t;
}
}
}
int findl(int k , int x)
{
if(!k) return 0;
else if(x <= a[k].w) return findl(a[k].l , x);
else return findl(a[k].r , x) + a[a[k].l].si + 1;
}
int findr(int k , int x)
{
if(!k) return 0;
else if(x >= a[k].w) return findr(a[k].r , x);
else return findr(a[k].l , x) + a[a[k].r].si + 1;
}
void insert(int p , int a , int l , int r , int x)
{
add(root[x] , a);
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) insert(p , a , lson);
else insert(p , a , rson);
}
void erase(int p , int a , int l , int r , int x)
{
del(root[x] , a);
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) erase(p , a , lson);
else erase(p , a , rson);
}
int queryl(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e) return findl(root[x] , a);
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += queryl(b , e , a , lson);
if(e > mid) ans += queryl(b , e , a , rson);
return ans;
}
int queryr(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e) return findr(root[x] , a);
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += queryr(b , e , a , lson);
if(e > mid) ans += queryr(b , e , a , rson);
return ans;
}
int main()
{
int n , m , i , x;
long long ans = 0;
n = read() , m = read();
for(i = 1 ; i <= n ; i ++ )
v[i] = read() , insert(i , v[i] , 1 , n , 1) , ans += queryr(1 , i , v[i] , 1 , n , 1) , pos[v[i]] = i;
while(m -- )
{
x = read() , printf("%lld\n" , ans);
ans -= queryr(1 , pos[x] , x , 1 , n , 1) + queryl(pos[x] , n , x , 1 , n , 1);
erase(pos[x] , x , 1 , n , 1);
}
return 0;
}
【bzoj3295】[Cqoi2011]动态逆序对 线段树套SBT的更多相关文章
- bzoj3295: [Cqoi2011]动态逆序对(树套树)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- BZOJ3295: [Cqoi2011]动态逆序对(树状数组套主席树)
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 7465 Solved: 2662[Submit][Sta ...
- bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组
[bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...
- BZOJ3295 [Cqoi2011]动态逆序对 分治 树状数组
原文链接http://www.cnblogs.com/zhouzhendong/p/8678185.html 题目传送门 - BZOJ3295 题意 对于序列$A$,它的逆序对数定义为满足$i< ...
- bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- P3157 [CQOI2011]动态逆序对(树状数组套线段树)
P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...
- bzoj3295[Cqoi2011]动态逆序对 树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5987 Solved: 2080[Submit][Sta ...
- [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...
- 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...
随机推荐
- java—三大框架详解,其发展过程及掌握的Java技术慨括
Struts.Hibernate和Spring是我们Java开发中的常用关键,他们分别针对不同的应用场景给出最合适的解决方案.但你是否知道,这些知名框架最初是怎样产生的? 我们知道,传统的Java W ...
- 关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)
来到个新地方,新学习C#,前面看到C#的垃圾回收,Finalize和Dispose时,总是一知半解,迷迷糊糊.这次好了,前面连续两次面试问到这个问题,脑子里不是很清晰,加上用英文来表达,更是雪上加霜的 ...
- SOA架构设计案例分析
转载自:https://www.jdon.com/soa.html 首先Martin Fowler提出SOA歧义Service Oriented Ambiguity,认为"什么是SOA&qu ...
- utf8、ansii、unicode编码之间的转换
#include "stdafx.h"#include "windows.h"#include <iostream>#include <str ...
- 51nod——2487小b和环
dp[ i ][ 0 ] : 第i个位置不取 dp[ i ][ 1 ] : 第i个位置取 这样就可以得到状态转移方程: dp[i][0]=max(max(dp[i][0],dp[i-1][1]),dp ...
- 高级字符驱动之堵塞与非堵塞IO
/** *此实例涉及到线程的挂起与竞态,字符IO的堵塞与非堵塞 */ struct scull_pipe { wait_queue_head_t inp, outp; char *buffer, *e ...
- Spring @Transactional 浅谈
一般当我们在一个方法里面操作多个数据对象的可持久化操作时,我们通常这些操作能够成功一起事务提交成功.默认情况下,数据库处于自动提交模式.每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成 ...
- 用express框架实现反向代理
目前很多公司开发都是前后台分离开发,于是我用node起了一个服务,用node中的express框架实现了反向代理.(通俗易懂的讲就是我在我的电脑访问不到后台同事的电脑接口,这样做以后就可以在我本地访问 ...
- 原生node实现本地静态页面的展示
var http = require("http"); var fs = require("fs"); var url = require("url& ...
- [译]The Python Tutorial#3. An Informal Introduction to Python
3. An Informal Introduction to Python 在以下示例中,输入和输出以提示符(>>>和...)的出现和消失来标注:如果想要重现示例,提示符出现时,必须 ...