【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重建一下 注意 测试点 ...
随机推荐
- npm scripts的生命周期管理
我们平时阅读一些开源项目,可能会发现有些项目的package.json里的scripts区域定义的脚本很复杂,令人眼花缭乱. 其实这些脚本是有规律可循的.让我们从最简单的一个例子开始学习. 新建一个空 ...
- Thread源码分析-java8
1.Thread特性分析 守护线程Daemon 定性:支持性线程,主要用于程序中后台调度以及支持性工作. 当JVM中不存在Daemon线程时,JVM将会退出. 将一个线程设定为Daemon的方法: 调 ...
- Python基础篇 -- 列表
3.2 列表的增删改查 列表使用 [] 来表示,列表中每个元素与元素之间用逗号隔开 列表也有索引和切片 # 切片切出来的也是列表 lst = ["梅西", "内马 ...
- ubuntu 16.04 安装node.js 8.x
引自 https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-16-04#how-to-in ...
- 有C++特色的极乐净土
闲的没事瞎打的 在win7下会走调,需要将win7的beep系统文件改成xp的,且主机装有蜂鸣器才能正常收听. beep文件的度盘地址(不过应该没人为了听个这个去改系统文件)(P.S.如果想要尝试,尽 ...
- ios坐标系统
在写程序的时候发现,iOS下的坐标.位置很容易弄乱,特别是在不同的坐标系统中,必须完成弄明白一些概念才能做相应的变化,例如CoreImage和UIView的坐标系统就截然不同,一个是以屏幕的左上角为原 ...
- Linux基础学习-基本命令
基本命令 date命令 参数 作用 %t 跳格 %H 小时(00-23) %I 小时(00-12) %M 分钟(00-59) %S 秒(00-59) %j 今年中的第几天 [root@qdlinux ...
- 译文 编写一个loader
https://doc.webpack-china.org/contribute/writing-a-loader loader是一个导出了函数的node模块,当资源须要被这个loader所转换的时候 ...
- 项目之socket
客户端socket 客户端套接字完成的任务很统一,发送请求,接收请求结果 可以封装成一个方法 使用的tcp协议存在粘包问题,故需要自定义报头 import json import struct #项目 ...
- python中map()函数的用法讲解
map函数的原型是map(function, iterable, -),它的返回结果是一个列表. 参数function传的是一个函数名,可以是python内置的,也可以是自定义的. 参数iterabl ...