【BZOJ】【3295】【CQOI2011】动态逆序对
树套树
Orz zyf神犇
时光倒流……逆序处理,将删点改为加点,动态维护序列。
由于是动态,要加点,所以用树状数组;同时又需要求序列中求比当前元素大/小的元素个数,所以要用平衡树。
所以方法就是在树状数组的每个节点上维护一棵这个节点表示的区间的平衡树。
为什么这样做是对的呢?因为求<k的元素个数这类操作满足区间加法,所以可以把多棵平衡树上的结果(一棵平衡树表示一个区间)加起来,就是整个区间的结果。
(我一开始想成带修改的区间第K大那种做法了……就是树状数组套权值线段树……sigh)
WA:ans[m+1]需要初始化,样例是因为只剩一个数所以逆序对数为0,但是其他数据明显不会是这样……
/**************************************************************
Problem: 3295
User: Tunix
Language: C++
Result: Accepted
Time:8432 ms
Memory:122372 kb
****************************************************************/ //BZOJ 3295
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
#define CC(a,b) memset(a,b,sizeof(a))
using namespace std;
int getint(){
int v=,sign=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') sign=-; ch=getchar();}
while(isdigit(ch)) {v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=,M=,INF=~0u>>;
const double eps=1e-;
typedef long long LL;
/*******************template********************/
int n,m,tot,l[M],r[M],s[M],rnd[M],w[M],v[M];
#define L l[x]
#define R r[x]
inline void Push_up(int x){
s[x]=s[L]+s[R]+w[x];
}
inline void zig(int &x){
int t=L; L=r[t]; r[t]=x; s[t]=s[x]; Push_up(x); x=t;
}
inline void zag(int &x){
int t=R; R=l[t]; l[t]=x; s[t]=s[x]; Push_up(x); x=t;
}
void ins(int &x,int num){
if (!x){
x=++tot; v[x]=num; s[x]=w[x]=; L=R=; rnd[x]=rand(); return;
}
s[x]++;
if (v[x]==num) w[x]++;
else if(num<v[x]){
ins(L,num); if(rnd[L]<rnd[x]) zig(x);
}else{
ins(R,num); if(rnd[R]<rnd[x]) zag(x);
}
}
int rank(int x,int num){//比x小的数有多少个
if (!x) return ;
if (v[x]==num) return s[L];
else if(num<v[x]) return rank(L,num);
else return s[L]+w[x]+rank(R,num);
}
#undef L
#undef R
/**********************Treap********************/
int rt[N];
int ss[N];
void update(int x,int y){
for(int i=x;i<=n;i+=i&-i) ins(rt[i],y);
}
LL getbig(int x,int val){
int t=;
for(int i=x;i;i-=i&-i)
t+=s[rt[i]]-rank(rt[i],val);
return t;
}
LL getsml(int x,int y,int val){
int t1=,t2=;
for(int i=x;i;i-=i&-i)
t1+=rank(rt[i],val);
for(int j=y;j;j-=j&-j)
t2+=rank(rt[j],val);
return t2-t1;
}
void add(int x){
for(int i=x;i<=n;i+=i&-i) ss[i]++;
}
LL sum(int x){
int ans=;
for(int i=x;i;i-=i&-i) ans+=ss[i];
return ans;
}
/*********************Fenwick*******************/
struct data{
int v,pos;
bool operator < (const data&b) const{
return v<b.v;
}
}a[N],b[N],d[N];
LL ans[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
n=getint(); m=getint();
F(i,,n) a[i].v=getint(),a[i].pos=i,b[i]=a[i];
sort(b+,b+n+);
F(i,,m){
d[i].v=getint();
d[i].pos=b[d[i].v].pos;
}
F(i,,n) b[i]=a[i];
F(i,,m) b[d[i].pos].v=;
ans[m+]=; F(i,,n) if (b[i].v){
update(i,b[i].v);
ans[m+]+=sum(n)-sum(b[i].v);
add(b[i].v);
} D(i,m,){
ans[i]=ans[i+]+getbig(d[i].pos-,d[i].v)+getsml(d[i].pos,n,d[i].v);
update(d[i].pos,d[i].v);
}
F(i,,m) printf("%lld\n",ans[i]);
return ;
}
【BZOJ】【3295】【CQOI2011】动态逆序对的更多相关文章
- BZOJ 3295: [Cqoi2011]动态逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3865 Solved: 1298[Submit][Sta ...
- Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2886 Solved: 924[Submit][Stat ...
- bzoj 3295 [Cqoi2011]动态逆序对(cdq分治,BIT)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3295 [题意] n个元素依次删除m个元素,求删除元素之前序列有多少个逆序对. [思路] ...
- 【刷题】BZOJ 3295 [Cqoi2011]动态逆序对
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]
RT 传送门 首先可以看成倒着插入,求逆序对数 每个数分配时间(注意每个数都要一个时间)$t$,$x$位置,$y$数值 $CDQ(l,r)$时归并排序$x$ 然后用$[l,mid]$的加入更新$[mi ...
- BZOJ 3295 [CQOI2011]动态逆序对 (三维偏序CDQ+树状数组)
题目大意: 题面传送门 还是一道三维偏序题 每次操作都可以看成这样一个三元组 $<x,w,t>$ ,操作的位置,权值,修改时间 一开始的序列看成n次插入操作 我们先求出不删除时的逆序对总数 ...
- BZOJ 3295 [Cqoi2011]动态逆序对 ——CDQ分治
时间.位置.数字为三个属性. 排序时间,CDQ位置,树状数组处理数字即可. #include <cstdio> #include <cstring> #include < ...
- 【BZOJ 3295】动态逆序对 - 分块+树状数组
题目描述 给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数. 分析:分块+树状数组 (PS:本题的CDQ分治解法见下一篇) 首先将序列分成T块,每一块开一个树状数组,并且先把最初的 ...
- 【Bzoj 3295】 动态逆序对(树套树|CDQ分治)
[题意] 每次删除一个数,然后问删除前逆序对数. [分析] 没有AC不开心.. 我的树状数组套字母树,应该是爆空间的,空间复杂度O(nlogn^2)啊..哭.. 然后就没有然后了,别人家的树套树是树状 ...
随机推荐
- iframe滚动条的一些方法
用iframe布局,会碰到浏览器右边出现2个滚动条,简单代码解决用iframe布局,会碰到浏览器右边出现2个滚动条, 简单代码解决,用下面的代码可以把浏览器本身的滚动条去掉,只留页面产生的滚动条: b ...
- Linux下DNS服务器的基本搭建
技术交流群:286866978 安装与配置 1. 装载光驱 2. 卸载光驱 3. 将安装包放在合适的文件夹并解压(有的更换光盘需要重新装载) 4. 安装 5. 重定向配置文件 6. 配置named.c ...
- android 数据库中的事务_银行转账示例
主java package com.itheima.transtation; import com.itheima.transtation.db.BankOpenHelper; import andr ...
- nyoj---t448(寻找最大数)
描述 请在整数 n 中删除m个数字, 使得余下的数字按原次序组成的新数最大, 比如当n=92081346718538,m=10时,则新的最大数是9888 输入 第一行输入一个正整数T,表示有T组测 ...
- C语言1-100连加,求质数,算瑞年检测字母大小写,登录系统
#include <stdio.h> void test(){//1+2+3+4+.....+100 int a,b; a=0; b=0; for ( ; a<=100; a++) ...
- 《Usermod:user lee is currently logged in 家目录不能改变解决方法》
前面短时间自己玩samba服务时,上面的所有服务都做好了,家目录死活就是不能访问,删掉自己的smb.conf文件,自己到别的服务上用rsync同步过来的文件,启动服务家目录还是不能访问,排了一下午,终 ...
- zynq 之u-boot
u-boot 启动文件分析 u-boot首先执行的文件:C:\Users\summer_spinach\Desktop\zynq_linux相关\linux\uboot内核\u-boot-xarm\a ...
- 【Sharing】开发与研发
[声明]此文为转载,只为收藏. 按:这几天我一直在写这篇东西,本来是胸有成竹,没想到后来越写越发现自己在这个题目下有太多话想说,而以我现在的能力又不能很好地概括总结,以至于越写越长,文章结构也变得混乱 ...
- PHP弱类型安全问题笔记
一.类型转换问题 intval(); var_dump(intval('1asdfasd')); //1 var_dump(intval('awqw12')); //0 var_dump(i ...
- 如何开启MYSQL远程连接权限
开启MYSQL远程连接权限 //建议设置固定IP mysql> GRANT ALL PRIVILEGES ON *.* TO root@"8.8.8.8" IDENTIFIE ...