【Luogu】P1393动态逆序对(树套树)
树套树。
每次删掉x的时候会减去1到x-1里比x位置的数大的数和它构成的逆序对,以及x+1到n里比x位置的数小的数和它构成的逆序对。
顺带一提我发现平衡树insert的时候不是要splay一下嘛
如果改成每插入50个splay一下会快的飞起
我这道题就是这么卡过去的23333
放上代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<algorithm>
#define mid ((l+r)>>1)
#define left (rt<<1)
#define right (rt<<1|1)
#define lson l,mid,left
#define rson mid+1,r,right
using namespace std;
int CNT; inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} int root[];
int q[]; struct Splay{
struct Node{
int size,sum,e[],val,fa;
}tree[];
int point,tot;
Splay(){ point=tot=; }
inline int iden(int x){ return x==tree[tree[x].fa].e[]; }
inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; }
inline void update(int x){
tree[x].size=tree[x].sum;
if(tree[x].e[]) tree[x].size+=tree[tree[x].e[]].size;
if(tree[x].e[]) tree[x].size+=tree[tree[x].e[]].size;
}
void rotate(int x,int rt){
int y=tree[x].fa; int r=tree[y].fa;
if(root[rt]==y) root[rt]=x;
int sony=iden(x),sonr=iden(y);
int b=tree[x].e[sony^];
connect(b,y,sony);
connect(y,x,sony^);
connect(x,r,sonr);
update(y);update(x);
}
void splay(int pos,int to,int rt){
to=tree[to].fa;
while(tree[pos].fa!=to){
if(tree[tree[pos].fa].fa==to) rotate(pos,rt);
else
if(iden(pos)==iden(tree[pos].fa)){ rotate(tree[pos].fa,rt); rotate(pos,rt); }
else{ rotate(pos,rt); rotate(pos,rt); }
}
}
int create(int val,int fa){
tree[++tot].val=val; tree[tot].sum=tree[tot].size=; tree[tot].fa=fa;
return tot;
}
int find(int val,int rt){
int now=root[rt];
while(){
if(!now) return ;
if(tree[now].val==val){
splay(now,root[rt],rt);
return now;
}
int nxt=val>tree[now].val?:;
if(!tree[now].e[nxt]) return ;
now=tree[now].e[nxt];
}
}
int build(int val,int rt){
point++;
if(!root[rt]){
root[rt]=create(val,);
return root[rt];
}
int now=root[rt];
while(){
tree[now].size++;
if(tree[now].val==val){
tree[now].sum++;
return now;
}
int nxt=val>tree[now].val?:;
if(!tree[now].e[nxt]){
int p=create(val,now);
connect(p,now,nxt);
return p;
}
now=tree[now].e[nxt];
}
}
void insert(int val,int rt){
int p=build(val,rt);
if((++CNT)%==){
splay(p,root[rt],rt);
CNT=;
}
}
void dele(int x){
tree[x].e[]=tree[x].e[]=;
if(x==tot) tot--;
}
void pop(int val,int rt){
int deal=find(val,rt);
if(!deal) return;
point--;
if(tree[deal].sum>){ tree[deal].sum--; tree[deal].size--; return;}
if(!tree[deal].e[]){
root[rt]=tree[deal].e[];
tree[root[rt]].fa=;
}
else{
int le=tree[deal].e[];
while(tree[le].e[]) le=tree[le].e[];
splay(le,tree[deal].e[],rt);
int ri=tree[deal].e[];
connect(ri,le,); tree[le].fa=;
root[rt]=le;
update(le);
}
dele(deal);
}
int rank(int val,int rt){
int ans=,now=root[rt];
while(){
if(!now) return ans;
if(tree[now].val==val){
ans+=tree[tree[now].e[]].size;
return ans;
}
if(val<tree[now].val) now=tree[now].e[];
else{
ans+=tree[tree[now].e[]].size+tree[now].sum;
now=tree[now].e[];
}
}
}
int arank(int val,int rt){
int ans=,now=root[rt];
while(){
if(!now) return ans;
if(tree[now].val==val){
ans+=tree[tree[now].e[]].size;
return ans;
}
if(val<tree[now].val){
ans+=tree[tree[now].e[]].size+tree[now].sum;
now=tree[now].e[];
}
else now=tree[now].e[];
}
}
int ask(int val,int rt,int opt){
if(opt==) return arank(val,rt);
else return rank(val,rt);
}
}s; void build(int l,int r,int rt){
for(int i=l;i<=r;++i) s.insert(q[i],rt);
if(l==r) return;
build(lson);
build(rson);
} int query(int from,int to,int val,int l,int r,int rt,int opt){
if(from>to) return ;
if(from<=l&&to>=r) return s.ask(val,rt,opt);
int cnt=;
if(from<=mid) cnt+=query(from,to,val,lson,opt);
if(to>mid) cnt+=query(from,to,val,rson,opt);
return cnt;
} void Delete(int o,int val,int l,int r,int rt){
s.pop(val,rt);
if(l==r) return;
if(o<=mid) Delete(o,val,lson);
else Delete(o,val,rson);
} int ans; int main(){
int n=read(),m=read();
for(int i=;i<=n;++i) q[i]=read();
build(,n,);
for(int i=;i<=n;++i) ans+=query(,i-,q[i],,n,,);
printf("%d",ans);
for(int i=;i<=m;++i){
int pos=read();
ans-=query(,pos-,q[pos],,n,,);
ans-=query(pos+,n,q[pos],,n,,);
printf(" %d",ans);
Delete(pos,q[pos],,n,);
}
return ;
}
【Luogu】P1393动态逆序对(树套树)的更多相关文章
- 【BZOJ3295】动态逆序对(线段树,树状数组)
[BZOJ3295]动态逆序对(线段树,树状数组) 题面 Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的 ...
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...
- P1393 动态逆序对
题目 P1393 动态逆序对 做题前写篇博客是个好方法 做法 题目规定仅有删除,给每个位置标个号,逆序对+时间轴,显然这是个三维偏序 很久没做过\(cdq\)了,就当模板题讲一下: 按删除的先后顺序为 ...
- [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...
- bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)
3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...
- [bzoj3295][Cqoi2011]动态逆序对_主席树
动态逆序对 bzoj-3295 Cqoi-2011 题目大意:题目链接. 注释:略. 想法:直接建立主席树. 由于是一个一个删除,所以我们先拿建立好的root[n]的权值线段树先把总逆序对求出来,接着 ...
- 洛谷P1393 动态逆序对(CDQ分治)
传送门 题解 听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大 ...
- BZOJ3295/Luogu3157 [CQOI2011]动态逆序对 (CDQ or 树套树 )
/* Dear friend, wanna learn CDQ? As a surprice, this code is totally wrong. You may ask, then why yo ...
- bzoj3295 洛谷P3157、1393 动态逆序对——树套树
题目:bzoj3295 https://www.lydsy.com/JudgeOnline/problem.php?id=3295 洛谷 P3157(同一道题) https://www.luogu.o ...
随机推荐
- Visual Studio 2005 移植 (札记之一)【zhuan】
Visual Studio 2005 移植 - WINVER,warning C4996, error LINK1104 一.WINVER Compile result: WINVER not d ...
- eclipse版本要求修改
eclipse要求打开的是java1.6,而安装的是java1.7,这个时候需要修改配置 找到JAVA的安装路径, 点击前往-电脑-资源库-Java-javaVCirtualMachines-...- ...
- Spring Boot: Spring Starter Project
好久没有创建过新项目,楼主发现Spring Boot项目创建失败了!!! 其中有两处错误: [图一不知道是哪里错,果断删掉重输入一次.成功进入下一步 其余步骤也没有错误,然而 最后一步失败了,如图 ...
- 洛谷 P1734 最大约数和
题目描述 选取和不超过S的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大. 输入输出格式 输入格式: 输入一个正整数S. 输出格式: 输出最大的约数之和. 输入输出样例 输入样例#1: 1 ...
- 编译驱动链接到了Kernel32库问题
最近开始学习驱动编程,根据网上的配置方法配置了驱动开发环境,用了一个简单的例子测试发现驱动居然链接到了kerner32库里面去了如图 : 显然是把Kernel.lib添加到了附加依赖库 如图 : 去掉 ...
- Codeforces Round #318 (Div. 2) A Bear and Elections (优先队列模拟,水题)
优先队列模拟一下就好. #include<bits/stdc++.h> using namespace std; priority_queue<int>q; int main( ...
- RMQ求区间最大最小值
#include<iostream> #include<cmath> #include<cstdio> #define N 50005 using namespac ...
- C# Process.Start方法
System.Diagnostics.Process.Start(); 主要功能: 1.打开某个链接网址(弹窗). 2.定位打开某个文件目录. 3.打开系统特殊文件夹,如“控制面板”等. Proces ...
- Schur 三角化定理的推论
将学习到什么 从 Schur 的酉三角化定理可以收获一批结果,在这一部分介绍重要的几个. 迹与行列式 相似矩阵具有相同的特征多项式, 从特征多项式一节中, 我们又知道,相似矩阵的迹以及行列式都是相 ...
- selenium-元素的定位
前戏 元素的定位是自动化测试的核心,要想操作一个元素,首先应该识别这个元素.Webdriver 提供了一系列的元素定位方法,常用的有 id,name,class name,link text,part ...