白白的(baibaide)——树状数组套主席树+splay
题目
【题目描述】
有一个长度为 $n$ 的序列 $a_1, a_2, \dots, a_n$,一开始每个位置都是白色。如果一个区间中每个位置都是白色,则称这是一个白白的区间。如果一个白白的区间向左或向右延长后都不是白白的区间了,则称这是一个极长的白白的区间。有 $q$ 次操作,每次操作会修改某个位置的值,或者把某个位置变成黑色。每次操作后,求所有极长的白白的区间中含有的逆序对数的异或和。强制在线。
【输入格式】
第一行两个正整数 $n, q$。
第二行 $n$ 个正整数 $a_1, a_2, \dots, a_n$。
接下来 $q$ 行,每行表示一次操作,每行的第一个数表示操作的种类:
$• ~ 0 ~ x ~ y$ 表示把 $a_x$ 改为 $y$
$• ~ 1 ~ x$ 表示把第 $x$ 个位置变成黑色
保证每次操作时的第 $x$ 个位置是白色的。
$x$ 和 $y$ 需要异或上一次输出的答案(若是第一次操作则无需异或)。
【输出格式】
$q$ 行,每行一个整数,表示每次询问的答案。
【样例输入】
4 3
6 0 10 1
1 2
1 0
1 2
【样例输出】
1
1
0
【数据范围与提示】
$n ≤ 150000,q ≤ 20000,0 ≤ a_i ≤ 10^9,1 ≤ x ≤ n,0 ≤ y ≤ 10^9$
$Subtask1(10pts) : n ≤ 10^3, q ≤ 10^3$
$Subtask2(20pts) : 只有 0 操作$
$Subtask3(30pts) : 只有 1 操作$
$Subtask4(40pts) : 没有特殊限制$
题解
这是一道极其毒瘤的数据结构题
求一段区间的逆序对个数,自然是用树状数组,但要支持修改和分裂,那么就套主席树,启发式分裂
效率:$ O(nlog^3n) $,很遗憾,这样子常数太大,而且这道题卡常
出题人发现,其实修改和分裂是可以分开做的
修改时直接在树套树上查询和修改即可,至于分裂时,其实要找的只有在它前面比它大的个数,可以每一个区间开一个 splay 查询,类似于启发式,暴力删,然后重构一个新的 splay
其实就是利用分裂时的特殊性质用 splay 优化树套树的分裂过程
大概要分讨一下前面的区间和后面的区间的大小
时间效率:$ O(nlog^2n)$
写到醉生梦死
代码
#include<bits/stdc++.h>
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
int R(){
int x;bool f=;char ch;_(!)if(ch=='-')f=;x=ch^;
_()x=(x<<)+(x<<)+(ch^);return f?x:-x;}
const int N=2e5+,INF=1e9+;
int n,q,a[N],Rt[N],li[N];
LL ans,las,sum[N];
set<int>s;
set<int>::iterator it;
class Splay{
private:
#define Ls(x) ch[x][0]
#define Rs(x) ch[x][1]
public:
int val[N*],fa[N*],siz[N*],num[N*],ch[N*][],cnt;
void pushup(int x){siz[x]=siz[Ls(x)]+siz[Rs(x)]+num[x];}
int init(){
cnt+=;
fa[cnt]=cnt-,Rs(cnt-)=cnt;
val[cnt]=INF,val[cnt-]=;
siz[cnt]=siz[cnt-]=num[cnt]=num[cnt-]=;
return cnt-;
}
int find_xi(int rt,int x){
if(!rt)return ;
if(val[rt]==x)return rt;
if(val[rt]<x){
int f=find_xi(Rs(rt),x);
return f?f:rt;
}
return find_xi(Ls(rt),x);
}
int find_da(int rt,int x){
if(!rt)return ;
if(val[rt]==x)return rt;
if(val[rt]>x){
int f=find_da(Ls(rt),x);
return f?f:rt;
}
return find_da(Rs(rt),x);
}
void rotate(int &k,int x){
int y=fa[x],z=fa[y],fl=(Rs(y)==x),w=ch[x][!fl];
if(y==k)k=x;
else ch[z][Rs(z)==y]=x;
ch[x][!fl]=y,ch[y][fl]=w;
if(w)fa[w]=y;fa[y]=x,fa[x]=z;
pushup(y),pushup(x);
return;
}
void splay(int &k,int x){
while(x!=k){
int y=fa[x];
if(y!=k)
rotate(k,(Ls(fa[x])==x)^(Ls(fa[y])==y)?x:y);
rotate(k,x);
}
}
void insert(int id,int x,int v){
int now=find_xi(Rt[id],x);
if(val[now]==x){
splay(Rt[id],now),num[now]+=v,pushup(now);
return;
}
int nex=find_da(Rt[id],x);
splay(Rt[id],now),splay(Rs(now),nex);
cnt++,val[cnt]=x,num[cnt]=siz[cnt]=;
fa[cnt]=nex,ch[nex][]=cnt;
pushup(nex),pushup(now);
return;
}
#undef Ls
#undef Rs
}T;
int cnt,rot[N];
struct seg{int ls,rs,v;}tr[N*];
#define Ls tr[rt].ls
#define Rs tr[rt].rs
LL query(int rt,int l,int r,int ql,int qr){
if(!rt)return ;
if(ql<=l&&qr>=r)return tr[rt].v;
int mid=(l+r)>>;LL res=;
if(ql<=mid)res=query(Ls,l,mid,ql,qr);
if(qr>mid)res+=query(Rs,mid+,r,ql,qr);
return res;
}
void insert(int &rt,int l,int r,int k,int v){
if(!rt)rt=++cnt;tr[rt].v+=v;
if(l==r)return;
int mid=(l+r)>>;
if(k<=mid)insert(Ls,l,mid,k,v);
else insert(Rs,mid+,r,k,v);
return;
}
LL ask(int l,int r,int ql,int qr){
if(ql>qr||l>r)return ;
LL ans=;
for(;r;r-=r&-r)ans+=query(rot[r],,INF,ql,qr);
for(;l;l-=l&-l)ans-=query(rot[l],,INF,ql,qr);
return ans;
}
void add(int k,int x,int f){for(;k<=n;k+=k&-k)insert(rot[k],,INF,x,f);}
int main(){
n=R(),q=R(),Rt[n]=T.init();
for(int i=;i<=n;i++)
a[i]=R()+,T.insert(n,a[i],);
s.insert(n),li[n]=;
for(int i=;i<=n;i++){
ans+=ask(,i-,a[i]+,INF);
add(i,a[i],);}
sum[n]=ans;
while(q--){
int op=R(),x=(LL)R()^las,y,l,r;
it=s.lower_bound(x);
r=(*it),l=li[r],ans^=sum[r];
if(!op){
y=(LL)(R()^las)+;
sum[r]-=ask(l-,x-,a[x]+,INF)+ask(x,r,,a[x]-);
T.insert(r,a[x],-),T.insert(r,y,);
add(x,a[x],-),add(x,a[x]=y,);
sum[r]+=ask(l-,x-,a[x]+,INF)+ask(x,r,,a[x]-);
ans^=sum[r];
}
if(op){
li[r]=x+,T.insert(r,a[x],-);
s.insert(x-),li[x-]=l,sum[x-]=;
LL num=(LL)ask(l-,x-,a[x]+,INF)+ask(x,r,,a[x]-);
if(x-l<r-x){
if(l!=x)Rt[x-]=T.init();
for(int i=l;i<x;i++){
T.insert(r,a[i],-);
int k=T.find_da(Rt[r],a[i]);
T.splay(Rt[r],k),num+=T.siz[T.ch[k][]];
T.insert(x-,a[i],);
k=T.find_da(Rt[x-],a[i]);
T.splay(Rt[x-],k);
sum[x-]+=T.siz[T.ch[k][]];
}
sum[r]-=num,ans^=sum[x-]^sum[r];
}
else{
swap(sum[r],sum[x-]),swap(Rt[r],Rt[x-]);
Rt[r]=T.init(),sum[r]=;
for(int i=r;i>x;i--){
T.insert(x-,a[i],-);
int k=T.find_da(Rt[x-],a[i]);
T.splay(Rt[x-],k),num+=T.siz[T.ch[k][]];
T.insert(r,a[i],);
k=T.find_da(Rt[r],a[i]);
T.splay(Rt[r],k);
sum[r]+=T.siz[T.ch[k][]];
}
sum[x-]-=num,ans^=sum[x-]^sum[r];
}
}
printf("%lld\n",las=ans);
}
return ;
}
白白的(baibaide)——树状数组套主席树+splay的更多相关文章
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树
BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...
- ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解
题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...
- P2617 Dynamic Rankings(树状数组套主席树)
P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...
- [COGS257]动态排名系统 树状数组套主席树
257. 动态排名系统 时间限制:5 s 内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...
- BZOJ 2141 排队(树状数组套主席树)
解法很多的题,可以块套树状数组,可以线段树套平衡树.我用的是树状数组套主席树. 题意:给出一段数列,m次操作,每次操作是交换两个位置的数,求每次操作后的逆序对数.(n,m<=2e4). 对于没有 ...
- 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】
题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...
- Codeforces Round #404 (Div. 2) E. Anton and Permutation(树状数组套主席树 求出指定数的排名)
E. Anton and Permutation time limit per test 4 seconds memory limit per test 512 megabytes input sta ...
- 【Luogu】P2617Dynamic Ranking(树状数组套主席树)
题目链接 树状数组套主席树有点难懂qwq 不好理解 树状数组套主席树的直观理解应该是:树状数组的每一个节点是一棵主席树. 普通区间修改我们是创建1个线段树,树状数组套主席树的时候我们就创建log个线段 ...
随机推荐
- jsoup抓取网页内容
java项目有时候我们需要别人网页上的数据,怎么办?我们可以借助第三方架包jsou来实现,jsoup的中文文档,那怎么具体的实现呢?那就跟我一步一步来吧 最先肯定是要准备好这个第三方架包啦,下载地址, ...
- C#winform拖拽实现获得文件路径
1.关键知识点说明: 通过DragEnter事件获得被拖入窗口的“信息”(可以是若干文件,一些文字等等),在DragDrop事件中对“信息”进行解析.窗体的AllowDrop属性必须设置成true;且 ...
- django-pagination分页
1. 将该APP安装至Django项目中.(settings.py) INSTALLED_APPS = ( # ... 'pagination', ) 2. 在Django项目的middleware中 ...
- STL stl_construct.h
stl_construct.h // Filename: stl_construct.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog ...
- px-rem自适应转换(进阶@rem:40rem; )
接力之前的文章 https://www.cnblogs.com/leshao/p/5674710.html 这篇文章讲解的是px -rem 单位换算 除100的 写法 比如实际测量PSD宽度是500 ...
- WPF中Xaml编译正常而Designer Time时出错的解决办法
开发wpf时我们经常遇到一个xaml文件在设计时显示解析错误(比如在:VS或者Blend)而编译正常运行正常. 原因是:xaml的在Debug版本下必须为anyCPU. 解决办法: 1.打开工程文件x ...
- poj 2388 Who's in the Middle(快速排序求中位数)
一.Description FJ is surveying his herd to find the most average cow. He wants to know how much milk ...
- spring初始化顺序
首先,Spring bean的默认加载顺序是怎么控制的 工程中有2个bean,A和B,其中必须先初始化A再初始化B,但是没有depend-on或者Order等方式去保证,只不过恰好刚好这么运行着没出事 ...
- oracle--分页过程demo1
oracle分页过程demo1: --ROWNUM用法 select o.*,rownum rn from (select * from emp) o where rownum<=10; sel ...
- Linux 文件名颜色
在Linux中,文件的颜色都是有含义的.其中, 蓝色表示目录 绿色表示可执行文件 红色表示压缩文件 浅蓝色表示链接文件 灰色表示其它文件 红色闪烁表示链接的文件有问题了 黄色是设备文件,包括block ...