(又是一道树套树……自己真是玩疯了……)

(题意略)

从网上也看过题解,好像解法很多……比如CDQ+树状数组,树状数组套主席树,树状数组套平衡树……我用的是树状数组套splay。

(我会说是因为我不会写CDQ和树状数组套主席树么= =)

(不得不吐槽,为啥splay这么快= =)

也没啥可说的,我写的是在线算法,只要在删除一个元素之前统计它前面比它大的数和后面比它小的数的个数(区间求和用树状数组,统计比它小/大的数的个数用平衡树写),把答案减掉对应数值即可。

鉴于这题卡常,我就加了快读和各种inline卡常大法,然后卡了不下5次评测机才过……(COGS垃圾评测机)

顺便一提,求初始逆序对可以用归并排序or树状数组,我用的是后者。

贴个代码(貌似这是全程非递归):

#include<cstdio>
#include<cstring>
#include<algorithm>
#define siz(x) ((x)?(x)->size:0)
#define lowbit(x) ((x)&(-(x)))
using namespace std;
namespace mine{
template<class T>inline void readint(T &__x){
static int __c;
static bool __neg;
__x=;
__neg=false;
do __c=getchar();while(__c==' '||__c=='\n'||__c=='\r'||__c=='\t');
if(__c=='-'){
__neg=true;
__c=getchar();
}
for(;__c>=''&&__c<='';__c=getchar())__x=__x*+(__c^);
if(__neg)__x=-__x;
}
template<class T>inline void putint(T __x){
static int __a[],__i,__j;
static bool __neg;
__neg=__x<;
if(__neg)__x=-__x;
__i=;
do{
__a[__i++]=__x%(T)^(T);
__x/=;
}while(__x);
if(__neg)putchar('-');
for(__j=__i-;__j^-;__j--)putchar(__a[__j]);
}
}
using namespace mine;
const int maxn=;
struct node{//Splay Tree
int data,size;
node *lc,*rc,*prt;
node(int d=):data(d),size(),lc(NULL),rc(NULL),prt(NULL){}
inline void refresh(){size=siz(lc)+siz(rc)+;}
}*root[maxn]={NULL};
void add(int);
void query(int);
void build(int,int);
int qlss(int,int);
int qgrt(int,int);
void mdel(int,int);
void insert(node*,int);
node *find(int,int);
void erase(node*,int);
int rank(int,int);
int rerank(int,int);
void splay(node*,node*,int);
void lrot(node*,int);
void rrot(node*,int);
node *findmax(node*);
int n,m,a[maxn],b[maxn],c[maxn]={},x;
long long ans=0ll;
int main(){
#define MINE
#ifdef MINE
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
#endif
readint(n);
readint(m);
for(int i=;i<=n;i++){
readint(a[i]);
b[a[i]]=i;
query(a[i]);
add(a[i]);
build(i,a[i]);
}
while(m--){
putint(ans);
putchar('\n');
readint(x);
x=b[x];
ans-=(long long)qgrt(x,a[x])+(long long)qlss(n,a[x])-(long long)qlss(x-,a[x]);
mdel(x,a[x]);
}
#ifndef MINE
printf("\n--------------------DONE--------------------\n");
for(;;);
#endif
return ;
}
inline void add(int x){
while(x){
c[x]++;
x-=lowbit(x);
}
}
inline void query(int x){
while(x<=n){
ans+=c[x];
x+=lowbit(x);
}
}
inline void build(int x,int d){
while(x<=n){
insert(new node(d),x);
x+=lowbit(x);
}
}
inline int qlss(int x,int d){
int ans=;
while(x){
ans+=rank(d,x);
x-=lowbit(x);
}
return ans;
}
inline int qgrt(int x,int d){
int ans=;
while(x){
ans+=rerank(d,x);
x-=lowbit(x);
}
return ans;
}
inline void mdel(int x,int d){
while(x<=n){
erase(find(d,x),x);
x+=lowbit(x);
}
}
inline void insert(node *x,int i){
if(!root[i]){
root[i]=x;
return;
}
node *rt=root[i];
for(;;){
if(x->data<rt->data){
if(rt->lc)rt=rt->lc;
else{
rt->lc=x;
break;
}
}
else{
if(rt->rc)rt=rt->rc;
else{
rt->rc=x;
break;
}
}
}
x->prt=rt;
for(;rt;rt=rt->prt)rt->refresh();
splay(x,NULL,i);
}
inline node *find(int x,int i){
node *rt=root[i];
while(rt){
if(x==rt->data)return rt;
else if(x<rt->data)rt=rt->lc;
else rt=rt->rc;
}
return NULL;
}
inline void erase(node *x,int i){
splay(x,NULL,i);
if(x->lc){
splay(findmax(x->lc),x,i);
x->lc->rc=x->rc;
if(x->rc)x->rc->prt=x->lc;
x->lc->prt=NULL;
root[i]=x->lc;
x->lc->refresh();
}
else{
if(x->rc)x->rc->prt=NULL;
root[i]=x->rc;
}
delete x;
}
inline int rank(int x,int i){
node *rt=root[i],*y=NULL;
int ans=;
while(rt){
y=rt;
if(x<=rt->data)rt=rt->lc;
else{
ans+=siz(rt->lc)+;
rt=rt->rc;
}
}
if(y)splay(y,NULL,i);
return ans;
}
inline int rerank(int x,int i){
return siz(root[i])-rank(x+,i);
}
inline void splay(node *x,node *tar,int i){
for(node *rt=x->prt;rt!=tar;rt=x->prt){
if(rt->prt==tar){
if(x==rt->lc)rrot(rt,i);
else lrot(rt,i);
break;
}
if(rt==rt->prt->lc){
if(x==rt->lc)rrot(rt,i);
else lrot(rt,i);
rrot(x->prt,i);
}
else{
if(x==rt->rc)lrot(rt,i);
else rrot(rt,i);
lrot(x->prt,i);
}
}
}
inline void lrot(node *x,int i){
node *y=x->rc;
if(x->prt){
if(x==x->prt->lc)x->prt->lc=y;
else x->prt->rc=y;
}
else root[i]=y;
y->prt=x->prt;
x->rc=y->lc;
if(y->lc)y->lc->prt=x;
y->lc=x;
x->prt=y;
x->refresh();
y->refresh();
}
inline void rrot(node *x,int i){
node *y=x->lc;
if(x->prt){
if(x==x->prt->lc)x->prt->lc=y;
else x->prt->rc=y;
}
else root[i]=y;
y->prt=x->prt;
x->lc=y->rc;
if(y->rc)y->rc->prt=x;
y->rc=x;
x->prt=y;
x->refresh();
y->refresh();
}
inline node *findmax(node *x){
while(x->rc)x=x->rc;
return x;
}

[CQOI2011]动态逆序对的更多相关文章

  1. BZOJ 3295: [Cqoi2011]动态逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3865  Solved: 1298[Submit][Sta ...

  2. Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2886  Solved: 924[Submit][Stat ...

  3. bzoj3295[Cqoi2011]动态逆序对 树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5987  Solved: 2080[Submit][Sta ...

  4. P3157 [CQOI2011]动态逆序对(树状数组套线段树)

    P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...

  5. P3157 [CQOI2011]动态逆序对

    P3157 [CQOI2011]动态逆序对 https://www.luogu.org/problemnew/show/P3157 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai&g ...

  6. 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)

    3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...

  7. [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...

  8. bzoj千题计划146:bzoj3295: [Cqoi2011]动态逆序对

    http://www.lydsy.com/JudgeOnline/problem.php?id=3295 正着删除看做倒着添加 对答案有贡献的数对满足以下3个条件: 出现时间:i<=j 权值大小 ...

  9. BZOJ3295: [Cqoi2011]动态逆序对(树状数组套主席树)

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7465  Solved: 2662[Submit][Sta ...

  10. 洛谷 P3157 [CQOI2011]动态逆序对 解题报告

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列\(A\),它的逆序对数定义为满足\(i<j\),且\(A_i>A_j\)的数对\((i,j)\)的个数.给\(1\)到\(n ...

随机推荐

  1. MySQL外键使用需要注意的几点

    最近刚刚接触MySQL,在建立表示遇到了一些问题,总是提示错误代码:150 can't create table ...,所以就到网上搜索了一下发现还有以下几点需要注意的: [CONSTRAINT [ ...

  2. Android学习笔记——Handler(一)

    使用Handler管理线程(转) 步骤: 1. 申请一个Handler对象 Handler handler = new Handler(); 2. 创建一个线程 {继承Thread类或者实现Runna ...

  3. Ubuntu——"xxx is not in the sudoers file.This incident will be reported" 错误解决方法

    Ubuntu下普通用户用sudo执行命令时报如题所示错误,解决方法就是在/etc/sudoers文件里给该用户添加权限.如下: 1.切换到root用户下 2./etc/sudoers文件默认是只读的, ...

  4. JSP 入门 HTML嵌套Java脚步 显示时间

    <%@ page import="java.util.Date"%> <%@ page language="java" contentType ...

  5. CodeForces 716B Complete the Word

    题目链接:http://codeforces.com/problemset/problem/716/B 题目大意: 给出一个字符串,判断其是否存在一个子串(满足:包含26个英文字母且不重复,字串中有‘ ...

  6. DIOCP 运作核心探密

    来自网友天地弦的DIOCP早已经广为人知了,有很多的同学都用上了它,甚至各种变异.修改版本也出了不少.我最近也在学习DIOCP,打算将它用于自己的服务端,今天让我们来一起探密它(DIOCP)的运作核心 ...

  7. Mongodb 资源

    一.资源 1.C# 驱动下载地址 https://github.com/mongodb/mongo-csharp-driver/releases 2. Mongodb 管理工具 mongochef 下 ...

  8. Jetty多Connector

    有时候想要启动两个端口,或者通过一个Jetty server提供多个不同服务,比如说使用8080来指定默认访问端口,使用8433指定https访问端口等等,此时就可以通过创建多个Connector来解 ...

  9. 代码重构 & 常用设计模式

    代码重构 重构目的 相同的代码最好只出现一次 主次方法 主方法 只包含实现完整逻辑的子方法 思维清楚,便于阅读 次方法 实现具体逻辑功能 测试通过后,后续几乎不用维护 重构的步骤 1  新建一个方法 ...

  10. 同一个解决方案"引用"其他的项目出现感叹号...

    项目A是自己新建的... 但是项目B是"添加"→"现有项目"添加的... 所以项目B引用项目A的时候,引用的项目A显示感叹号... 项目A右击"属性& ...