题目

【题目描述】

有一个长度为 $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的更多相关文章

  1. BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

    [题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...

  2. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  3. BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树

    BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...

  4. ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解

    题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...

  5. P2617 Dynamic Rankings(树状数组套主席树)

    P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...

  6. [COGS257]动态排名系统 树状数组套主席树

    257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...

  7. BZOJ 2141 排队(树状数组套主席树)

    解法很多的题,可以块套树状数组,可以线段树套平衡树.我用的是树状数组套主席树. 题意:给出一段数列,m次操作,每次操作是交换两个位置的数,求每次操作后的逆序对数.(n,m<=2e4). 对于没有 ...

  8. 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】

    题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...

  9. 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 ...

  10. 【Luogu】P2617Dynamic Ranking(树状数组套主席树)

    题目链接 树状数组套主席树有点难懂qwq 不好理解 树状数组套主席树的直观理解应该是:树状数组的每一个节点是一棵主席树. 普通区间修改我们是创建1个线段树,树状数组套主席树的时候我们就创建log个线段 ...

随机推荐

  1. 分析CSS布局中BFC

    1.什么是BFC BFC(Block Formatting Context,块级元素格式化上下文)是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和 ...

  2. JavaUtil_02_二维码的生成与解析

    1.引入jar包 zxing-core-1.7.jar  :   http://viralpatel.net/blogs/download/jar/zxing-core-1.7.jar zxing-j ...

  3. js事件绑定的几种方式与on()、bind()的区别

    版权声明:本文为博主原创文章,未经博主允许不得转载 一直不是很理解几种js事件绑定之间的区别与联系,今天百度了一下,在此做一总结: 1.如果只是简单的绑定一个事件,可以直接写在行内,点击执行一个函数, ...

  4. java--Hibernate添加数据save

    添加按钮跳转到add表单页面 <a href="${pageContext.request.contextPath }/department_saveUI.action"&g ...

  5. LeetCode Majority Element I

    原题链接在这里:https://leetcode.com/problems/majority-element/ 题目: Given an array of size n, find the major ...

  6. UILabel的富文本显示选项

    UILabel的富文本格式设置 1.实例化方法和使用方法 实例化方法: 使用字符串初始化 - (id)initWithString:(NSString *)str; 例: NSMutableAttri ...

  7. IIC编程1:i2c-tools使用

    安装: apt-get install libi2c-dev i2c-tools 检测i2c总线数目 用i2cdetect检测有几组i2c总线在系统上: i2cdetect -l 可以看到系统中有9组 ...

  8. kubeadm 搭建 K8S集群

    kubeadm是K8s官方推荐的快速搭建K8s集群的方法. 环境: Ubuntu 16.04 1 安装docker Install Docker from Ubuntu’s repositories: ...

  9. uboot的relocation原理详细分析

    转自:http://blog.csdn.net/skyflying2012/article/details/37660265 最近在一直在做uboot的移植工作,uboot中有很多值得学习的东西,之前 ...

  10. ASP.NET MVC 3:缓存功能的设计问题

    今天这一篇文章我来谈一谈在MVC 3项目中的缓存功能,以及针对缓存的一些设计上的考量,给大家参考参考. 为什么需要讨论缓存?缓存是一个中大型系统所必须考虑的问题.为了避免每次请求都去访问后台的资源(例 ...