【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重建一下 注意 测试点 ...
随机推荐
- 使用python批量导入txt导入excel表格(公司电脑设备ip和人员统计)
#!/bin/env python # -*- encoding: utf- -*- import datetime import time import os import sys import x ...
- python打飞机pro版
# -*- coding: utf-8 -*- import pygame from sys import exit import random pygame.init() screen = pyga ...
- Error:(3, 32) java: 程序包org.springframework.boot不存在
解决方案一: 找同事传一份D:\maven_repository\org\springframework\boot ,如图所示的位置,添加进去立刻就不报红.我也可以给你发.... 解决方案二: ...
- 【iview input 回车刷页面bug】input 就一个的时候 有form的时候 回车会刷页面,如果就一个input,可以不要form,或者form里面两个input 将一个input v-show false 就可以了
[iview input 回车刷页面bug]input 就一个的时候 有form的时候 回车会刷页面,如果就一个input,可以不要form,或者form里面两个input 将一个input v-sh ...
- chrom浏览器-F2使用方法一
由于F12是前端开发人员的利器,所以我自己也在不断摸索中,查看一些博客和资料后,自己总结了一下来帮助自己理解和记忆,也希望能帮到有需要的小伙伴,嘿嘿! 首先介绍Chrome开发者工具中,调试时使用最多 ...
- 用python编写九九乘法表
for i in range(1,10): for j in range(1,10): if j >i: print(end='') else: print(j,'*',i,'=',i*j,en ...
- 在Terminal中,如何打开Finder,并显示当前的目录
这是一个非常方便实用的小技巧,在Terminal中输入如下命令: $ open . 有图有真相: 参考: Open Finder in Current Folder from Terminal
- 两个input标签之间间隙问题的解决
<input type="text"> <input type="button" value="搜索"> 代码显示效 ...
- 【搜索 ex-BFS】bzoj2346: [Baltic 2011]Lamp
关于图中边权非零即一的宽度优先搜索 Description 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组 ...
- Java的BigDecimal容易出现的坑
BigDecimal一般是用来做要求比较高的精准计算的.前几天在使用的时候遇到一个大坑,记录下. 这个问题产生是使用BigDecimal做除法(divide)运算,这个类的divide方法存在三个常用 ...