luogu P5105 不强制在线的动态快速排序
前言
考试的时候居然想错了区间贡献,mdzz
思路
题目看着很方啊,难道要树套树?
但数据范围提醒我们,是nlogn的复杂度
Sort(S)的定义是不是很鬼畜
但我们不动脑子的打表容易发现
连续区间[1,n]内\(a_i^2-a_{i-1}^2\)为连续的奇数
(其实这里直接用初中的完全平方公式就好)
我们再次打表又发现了
连续的奇数的异或和,很有规律的嘛
可以直接O(1)求出
int xx(int x) {
if(x%4==0) return 0;
if(x%4==2) return 2;
if(x%4==1) return x+x-1;
return x+x+1;
}
根据异或的性质(a^a=0)
我们就能计算出任意连续一段的ans了,\(xx(l-1)\)^\(xx(r)\)
虽说允许重复的集合S
但区间如果重叠,他也只计算一次答案,手玩一下很容易看出
也就是集合S还是不允许重复的(重复的删掉是不影响答案的)
合并直接算就好了
我们现在需要一个只需要支持区间更改贡献的数据结构
lsh+线段树真香
struct node {
int l,r,lazy;
int mi,ma,sum;
int full,k;
} e[maxn<<4];
/*
mi,ma维护区间[l,r]最小值
lazy懒惰标记
ok判断区间[l,r]是否全部被计算答案
k判断[mid,mid+1]之间是否连接
ans就是ans啦
*/
ps:可能我的线段树调试的时候打了太多补丁,肯定有比我写的好得多的代码
但也是不难理解的,重要部分我们加以注释
关于int,是会炸的,反正我的数据灰渣
另外提醒
千万别开小了数组,一组询问是两个数偶,我一直报WA
错误
主席树写多了,左右孩子和l,r老是搞混了,mdzz
代码
#include <bits/stdc++.h>
#define ll long long
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=3e5+7;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int read() {
int x=0,f=1;char s=getchar();
for(; s>'9'||s<'0'; s=getchar()) if(s=='-') f=-1;
for(; s>='0'&&s<='9'; s=getchar()) x=x*10+s-'0';
return x*f;
}
ll xx(ll x) {
if(x%4==0) return 0;
if(x%4==2) return 2;
if(x%4==1) return x+x-1;
return x+x+1;
}
ll calc(ll l,ll r) {return xx(r)^xx(l-1);}
struct node {
int l,r;
ll mi,ma,sum;
bool full,k,lazy;
} e[maxn<<4];
int lsh[maxn<<1],len;
void pushup(int rt) {
if(e[rt].full) return;
if(e[rt].k) // 区间[mid,mid+1]贡献 需要计算
e[rt].sum=e[rt<<1].sum^e[rt<<1|1].sum^calc(lsh[e[rt<<1].r]+1,lsh[e[rt<<1|1].l]);
else if(e[rt<<1].ma==-inf||e[rt<<1|1].mi==inf) //只有一边有值
e[rt].sum=e[rt<<1].sum^e[rt<<1|1].sum;
else //暴力计算
e[rt].sum=e[rt<<1].sum^e[rt<<1|1].sum^(e[rt<<1|1].mi*e[rt<<1|1].mi-e[rt<<1].ma*e[rt<<1].ma);
e[rt].ma=max(e[rt<<1].ma,e[rt<<1|1].ma);
e[rt].mi=min(e[rt<<1].mi,e[rt<<1|1].mi);
}
void tag(int rt) {//区间全部计算ans
e[rt].sum=calc(lsh[e[rt].l]+1,lsh[e[rt].r]);
e[rt].full=1;
e[rt].mi=lsh[e[rt].l];
e[rt].ma=lsh[e[rt].r];
}
void pushdown(int rt) {
if(e[rt].lazy==0) return;
if(e[rt].lazy) {//显然
tag(rt<<1);tag(rt<<1|1);
e[rt<<1].lazy=e[rt<<1|1].lazy=1;
e[rt].lazy=0;
}
}
void build(int l,int r,int rt) {//显然
e[rt].l=l,e[rt].r=r;
e[rt].ma=-inf,e[rt].mi=inf;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void modify(int L,int R,int rt) {
if(L<=e[rt].l&&e[rt].r<=R) {
tag(rt);
e[rt].lazy=1;
return;
}
if(e[rt].full) return;//如果计算过就不用在计算了
pushdown(rt);
int mid=(e[rt].l+e[rt].r)>>1;
if(L<=mid) modify(L,R,rt<<1);
if(R>mid) modify(L,R,rt<<1|1);
if(L<=mid&&R>mid) e[rt].k=1;//区间两边都经过,中间也一定经过,k=1
pushup(rt);
}
struct edge {int opt,x,y;} Q[maxn];//询问
main() {
//read and lsh
int n=read();
FOR(i,1,n) {
Q[i].opt=read();
if(Q[i].opt==1) lsh[++len]=Q[i].x=read(),lsh[++len]=Q[i].y=read();
}
sort(lsh+1,lsh+1+len);
len=unique(lsh+1,lsh+1+len)-lsh-1;
build(1,len,1);
FOR(i,1,n) {
if(Q[i].opt==2) continue;
Q[i].x=lower_bound(lsh+1,lsh+1+len,Q[i].x)-lsh;
Q[i].y=lower_bound(lsh+1,lsh+1+len,Q[i].y)-lsh;
}
//work
FOR(i,1,n) {
if(Q[i].opt==2)
cout<<e[1].sum<<"\n";
else
modify(Q[i].x,Q[i].y,1);
}
return 0;
}
luogu P5105 不强制在线的动态快速排序的更多相关文章
- 洛谷 P5105 不强制在线的动态快速排序
P5105 不强制在线的动态快速排序 题目背景 曦月最近学会了快速排序,但是她很快地想到了,如果要动态地排序,那要怎么办呢? 题目描述 为了研究这个问题,曦月提出了一个十分简单的问题 曦月希望维护一个 ...
- P5105 不强制在线的动态快速排序
P5105 不强制在线的动态快速排序 $\bigoplus \limits_{i=2}^n (a_i^2-a_{i-1}^2) = \bigoplus \limits_{i=2}^n (a_i-a_{ ...
- [洛谷P5105]不强制在线的动态快速排序
题目大意:有一个可重集$S$,有两个操作: $1\;l\;r:$表示把$S$变为$S\cup[l,r]$ $2:$表示将$S$从小到大排序,记为$a_1,a_2,\dots,a_n$,然后求出$\bi ...
- luoguP5105 不强制在线的动态快速排序 [官方?]题解 线段树 / set
不强制在线的动态快速排序 题解 算法一 按照题意模拟 维护一个数组,每次直接往数组后面依次添加\([l, r]\) 每次查询时,暴力地\(sort\)查询即可 复杂度\(O(10^9 * q)\),期 ...
- luoguP5105 不强制在线的动态快速排序
emm 可重集合没用用.直接变成不可重复集合 有若干个区间 每个区间形如[L,R] [L,R]计算的话,就是若干个连续奇数的和.拆位统计1的个数 平衡树维护 加入一个[L,R],把相交的区间合并.之后 ...
- [Luogu5105]不强制在线的动态快速排序
首先集合去重不影响答案,然后打表易得连续自然数平方差异或前缀和的规律,于是问题就变为在线维护区间求并同时更新答案,set记录所有区间,每次暴力插入删除即可.由于每个区间至多只会插入删除一次,故均摊复杂 ...
- [EOJ439] 强制在线
Description 见EOJ439 Solution 先考虑不强制在线怎么做. 按询问区间右端点排序,从左往右扫,维护所有后缀的答案. 如果扫到 \(a[i]\),那么让统计个数的 \(cnt[a ...
- hihocoder #1236 Scores (15北京赛区网络赛J) (五维偏序,强制在线,bitset+分块)
链接:http://hihocoder.com/problemset/problem/1236 思路; 有n个五维的向量,给出q个询问,每个询问是一个五维向量,问有多少个向量没有一维比这个向量大.并且 ...
- [BZOJ 3720][JZYZOJ 2016]gty的妹子树 强制在线 树分块/树套树
jzyzoj的p2016 先码着,强制在线的树分块或者树套树?关键是我树分块还在入门阶段树套树完全不会啊摔 http://blog.csdn.net/jiangyuze831/article/de ...
随机推荐
- db2修改表结构,增加列,删除列等
增加一列:ALTER TABLE tbname ADD COLUMN columnName datatype; 增加多列:ALTER TABLE tbname ADD COLUMN columnNam ...
- ling join 报错The specified LINQ expression contains references to queries that are associated with different cont
The specified LINQ expression contains references to queries that are associated with different cont ...
- 【转】LoadRunner压力测试:测试报告结果分析
见:https://blog.csdn.net/haoui123/article/details/62036723
- WEB应用程序:AJAX全套
概述 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要 ...
- rt.jar sun package
安装完JDK后,会在%JAVA_HOME% /jdk文件夹下生成一个src.zip,此文件夹对应rt.jar中的java源码,但细心研究后发现rt.jar中sun包下的文件不存在,也就是说 ...
- HTTPS 之共享秘钥 公钥 及 私钥
HTTPS 之共享秘钥 公钥 及 私钥一 共享秘钥1.1 概念共享秘钥和我们生活中同一把锁的钥匙概念类似,对同一把锁来说,加锁时使用什么钥匙,解锁也必须使用同样的钥匙. 1.2 共享秘钥在HTTP传输 ...
- over(partition by)开窗函数的使用
开窗函数是分析函数中的一种,开窗函数与聚合函数的区别是:开窗函数是用于计算基于组的某种聚合值且每个的组的聚合计算结果可以有多行,而聚合函数每个组的聚合计算结果只有一个.使用开窗函数可以在没有group ...
- linux常用命令:more 命令
more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会 ...
- 【javascript】内存泄露及其解决办法
1.内存泄露:一般由于开发者使用不当导致不用的内存没有被操作系统或者空闲内存池回收释放. 2.造成内存泄露的常见原因: 1) 意外的全局变量引起的内存泄露 2)闭包引起的内存泄露 闭包可以维持函数内局 ...
- javanio2
package com.lanhuigu.nio.selector; import java.net.InetSocketAddress; import java.nio.ByteBuffer; im ...