【ZOJ4053】Couleur(主席树,set,启发式)
题意:
有n个位置,每个位置上的数字是a[i],现在有强制在线的若干个单点删除操作,每次删除的位置都不同,要求每次删除之后求出最大的连续区间逆序对个数
n<=1e5,1<=a[i]<=n
思路:
对于每次删除操作我们可以考虑被删除的数字的贡献
比如区间[l,r]内删除了x这个位置,被分成了[l,x-1]与[x+1,r]两个区间
未删除之前区间总逆序对数可以分为4个部分:[l,x-1]内部,[x+1,r]内部,跨区间,一端为x
一个优秀的结论是内部区间和跨区间部分可以选择两端区间内较小的一段进行暴力枚举计算(启发式),这样每个位置均摊被用到了logn次
然后用总的逆序对数减去其他3部分就是较大区间内部的逆序对数
逆序对部分等价于求某个区间内在[l,r]之间数字的个数,显然使用主席树进行预处理
现在还要维护区间的插入,删除与最大值,这个如果只使用一个splay似乎很难维护多个关键字
大佬new表示并不需要splay,只需要使用set维护被删除的点,就能很快找出被删除的位置处于哪个区间
然而我并不会set,只能照他打一遍了,真是屈辱
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
#define fi first
#define se second s
#define MP make_pair
#define N 110000
#define MOD 1000000007
#define eps 1e-8
#define pi acos(-1)
#define oo 1e9 struct node
{
int l,r,s;
}t[N*]; struct data
{
ll x;
int l,r;
}; ll Ans[N],f[N],ans;
int a[N],root[N],cnt,n; set<int>st;
typedef set<int>::iterator iter;
struct setcmp
{
bool operator()(const data &x,const data &y)
{
return x.x>y.x||(x.x==y.x&&x.l<y.l)||(x.x==y.x&&x.l==y.l&&x.r<y.r);
}
};
set<data,setcmp>S; ll query(int l,int r,int x,int y,int L,int R)
{
if(l>r||x>y) return ;
if(x<=l&&r<=y) return t[R].s-t[L].s;
int mid=(l+r)>>;
ll ans=;
if(x<=mid) ans+=query(l,mid,x,y,t[L].l,t[R].l);
if(y>mid) ans+=query(mid+,r,x,y,t[L].r,t[R].r);
return ans;
} void update(int l,int r,int x,int &p)
{
t[++cnt]=t[p];
p=cnt;
t[p].s++;
if(l==r) return;
int mid=(l+r)>>;
if(x<=mid) update(l,mid,x,t[p].l);
else update(mid+,r,x,t[p].r);
} int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} int main()
{
freopen("zoj4053.in","r",stdin);
freopen("zoj4053.out","w",stdout);
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
cnt=;
ans=;
st.clear();
st.insert();
st.insert(n+);
S.clear();
for(int i=;i<=n;i++)
{
root[i]=root[i-];
update(,n,a[i],root[i]);
}
ll ans=;
for(int i=;i<=n;i++) ans+=query(,n,a[i]+,n,root[],root[i-]);
S.insert((data){ans,,n});
f[]=ans;
for(int i=;i<=n;i++)
{
ans=(*S.begin()).x;
Ans[i]=ans;
ll x;
scanf("%lld",&x);
x^=ans;
iter p=st.lower_bound(x);
int r=*p;
p--;
int l=*p;
l++; r--;
S.erase(S.lower_bound((data){f[l],l,r}));
ans=f[l];
ll t1=;
ll t2=;
if(x-l<r-x)
{
for(int i=l;i<x;i++)
{
t1+=query(,n,,a[i]-,root[i],root[x-]);
ans-=query(,n,,a[i]-,root[i],root[r]);
}
ans-=query(,n,,a[x]-,root[x],root[r]);
t2=ans;
}
else
{
for(int i=x+;i<=r;i++)
{
t2+=query(,n,a[i]+,n,root[x],root[i-]);
ans-=query(,n,a[i]+,n,root[l-],root[i-]);
}
ans-=query(,n,a[x]+,n,root[l-],root[x-]);
t1=ans;
}
if(<=x-)
{
S.insert((data){t1,l,x-});
f[l]=t1;
}
if(x+<=r)
{
S.insert((data){t2,x+,r});
f[x+]=t2;
}
st.insert(x);
}
for(int i=;i<n;i++) printf("%lld ",Ans[i]);
printf("%lld\n",Ans[n]); }
return ;
}
【ZOJ4053】Couleur(主席树,set,启发式)的更多相关文章
- 【BZOJ3123】森林(主席树,启发式合并)
题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...
- [bzoj3123][Sdoi2013]森林_主席树_启发式合并
森林 bzoj-3123 Sdoi-2013 题目大意:给定一片共n个点的森林,T个操作,支持:连接两个不在一棵树上的两个点:查询一棵树上路径k小值. 注释:$1\le n,T \le 8\cdot ...
- 洛谷 P4755 - Beautiful Pair(主席树+分治+启发式优化)
题面传送门 wssb,我紫菜 看到这类与最大值统计有关的问题可以很自然地想到分治,考虑对 \([l,r]\) 进行分治,求出对于所有 \(l\le x\le y\le r\) 的点对 \((x,y)\ ...
- BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...
- 洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)
传送门 据说离线做法是主席树上树+启发式合并(然而我并不会) 据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了 这里先感谢LadyLex大佬的博客->这里 克鲁斯卡尔重构树 ...
- 白白的(baibaide)——树状数组套主席树+splay
题目 [题目描述] 有一个长度为 $n$ 的序列 $a_1, a_2, \dots, a_n$,一开始每个位置都是白色.如果一个区间中每个位置都是白色,则称这是一个白白的区间.如果一个白白的区间向左或 ...
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
随机推荐
- 微信程序开发系列教程(四)使用微信API创建公众号自定义菜单
大家可能经常看到一些微信公众号具有功能强大的自定义菜单,点击之后可以访问很多有用的功能. 这篇教程就教大家如何动手做一做. 这个教程最后实现的效果是:创建一个一级菜单"UI5", ...
- android-menudrawer-master 使用
1. 参照例子写, 运行总崩溃, 多半是导库问题... 2. 既然这样不行, 只好将源码全部拷贝到工程中了. 然后修错误, (将需要的res 文件复制过来.主要是value中的几个文件) 3. 在Ma ...
- webpack 使用流程
webpack loader 读文件的 脚手架 vue-cli: 自动化的小工具,帮咱们把项目的架子搭起来 -------------------------------------- 开发环境 n ...
- python之文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)的作用
'r':只读.该文件必须已存在. 'r+':可读可写.该文件必须已存在,写为追加在文件内容末尾. 'rb':表示以二进制方式读取文件.该文件必须已存在. 'w':只写.打开即默认创建一个新文件,如果文 ...
- ulimit 值超出允许范围导致无法登陆操作系统
在linux中,使用ulimit可以设置一些资源的使用限制. [root@root ~]# ulimit -a core file size (blocks, -c) unlimit ...
- ios之自定义UINavigationBar
ios5 自定义导航条问题 在ios5之前的系统中,可以通过定义导航条类别的方式自定义导航条: @implementation UINavigationBar (CustomImage)- (void ...
- 《offline coolbook》笔记
https://jakearchibald.com/2014/offline-cookbook/ 在install中对依赖进行缓存 self.addEventListener('install', f ...
- JavaScript正则表达式-边界符
^:表示字符串开始位置,在多行匹配中表示一行的开始位置. /^\w+/匹配字符串中第一个单词. $:表示字符串结束的位置,在多行匹配中表示一行的结束位置. /\w+$/匹配字符串中最后一个单词. /@ ...
- PAT Basic 1062
1062 最简分数 一个分数一般写成两个整数相除的形式:N/M,其中 M 不为0.最简分数是指分子和分母没有公约数的分数表示形式. 现给定两个不相等的正分数 N1/M1 和 N2/M ...
- Spring核心技术(十一)——基于Java的容器配置(一)
基本概念: @Bean和@Configuration Spring中新的基于Java的配置的核心就是支持@Configuration注解的类以及@Bean注解的方法. @Bean注解用来表示一个方法会 ...