[Ynoi2014]不归之人与望眼欲穿的人们
题目大意:
给定一个序列,每次单点修改一个数,或给定$x$,询问最短的or起来大于等于$x$的区间的长度(不存在输出-1)。
解题思路:
在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。————世界上最幸福的女孩
盼你归来,珂朵莉~
---
这些题目果然一道比一道神仙
众所周知,这道题分块。
然后你就珂以去看shadowice1984的题解了
好吧窝来复述一下吧(雾)
首先有一个结论,对于一个区间,如果其中一个端点固定,则区间or和的不同取值最多$\log a$个,因为or和是按位变大的(不会变小)。
先假设我们手里有一个已经分好块的序列,块大小为$S$,那么对于询问,就有两种情况:区间在一个块内,区间跨了几个块。
考虑处理出每个块内,长度为$len$的区间的最大异或和。然后对于区间在块内的情况,直接二分即可。单次询问复杂度$O(\frac{n\log S}{S})$。
由于有单点修改操作,我们还要考虑快速修改这个数组。根据刚刚说的结论,对每个点作端点,不同or和最多$\log a$个,所以处理出每个数的每一位在之后(包括自己)第一次出现的位置,然后按顺序or即可。
还有个问题,我们需要“按顺序”or,排序的话就会多一个$\log\log a$。
假设我们已经知道位置$i$要or的那些位置的顺序构成的队列,对于位置$i-1$,先把它出现过的位塞进队列,再从前往后扫描位置$i$的队列,把没出现在位置$i-1$的位塞进队列。这个队列就是第$i-1$位要转移的位置的顺序。单次复杂度$O(S\log a)$。
现在考虑跨块的区间。我们从左往右枚举块,处理以第$i$个块的块尾结尾的后缀的不同or和(同时记录位置)。
然后考虑第$i+1$个块的所有不同前缀,用双指针扫描后缀和前缀(左端点往右,右端点也往右),更新答案即可。
接着考虑如何从第$i$块的后缀转移到第$i+1$块的贡献。先把原来的后缀or上第$i+1$块所有数的or和,然后用归并排序把第$i+1$块的后缀并上去即可。最后去重,出现多次的保留最后出现的即可。
复杂度$O(\frac{n\log a}{S})$。
$S$取$\sqrt n$,得总复杂度$O(n\sqrt n\log n)$。
然后卡卡常数。
C++ Code:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<cstdio>
#include<cctype>
#include<utility>
#include<algorithm>
#include<cstring>
char buf[8888888],*it;
void init(){fread(it=buf,1,8888886,stdin);fclose(stdin);}
inline int readint(){
int d=0;
for(;!isdigit(*it);++it);
while(isdigit(*it))d=d*10+(*it++^'0');return d;
}
#define mp std::make_pair
#define bel(x)((x-1)/siz+1)
typedef std::pair<int,int>PII;
inline bool operator<(const PII&a,const PII&b){
return(a.first!=b.first)?a.first<b.first:a.second>b.second;
}
const int siz=400;
int a[60000];
inline void chkmax(int&a,const int&b){if(a<b)a=b;}
inline void chkmin(int&a,const int&b){if(a>b)a=b;}
int ans,pv;
PII q[23333],vec[66],c[66];
struct BLOCK{
int mx[402],val[402],L,R,cntp,cnts,all;
PII pre[33],suf[33];
void re(){
memset(mx,0,sizeof mx);
for(int i=1,p=cntp=0;i<=siz;++i)
if((p|=val[i])!=pre[cntp].first)pre[++cntp]=mp(p,i+L-1);
for(int i=siz,p=cnts=0;i;--i)
if((p|=val[i])!=suf[cnts].first)suf[++cnts]=mp(p,i+L-1);
int head=1,tail=0;
for(int i=siz;i;--i){
const int lst=tail,v=val[i];
for(int j=v;j;j^=j&-j)
q[++tail]=mp(__builtin_ctz(j),i);
for(int j=head;j<=lst;++j)
if(!(v>>q[j].first&1))q[++tail]=q[j];
head=lst+1;
for(int j=head,now=0;j<=tail;++j){
const int pos=q[j].second;
chkmax(mx[pos-i+1],now|=val[pos]);
}
}
for(int i=2;i<=siz;++i)chkmax(mx[i],mx[i-1]);
all=pre[cntp].first;
}
void build(int l,int r){
L=l,R=r;
for(int i=l;i<=r;++i)val[i-l+1]=a[i];
re();
}
void modify(int pos,int v){val[pos-L+1]=v;re();}
inline int getlen(int v){return std::lower_bound(mx+1,mx+siz+1,v)-mx;}
inline void merge_suffix_to_vec(){
int l=1,r=1,it=1;
while(l<=pv&&r<=cnts)
c[it++]=(vec[l]<suf[r])?vec[l++]:suf[r++];
while(l<=pv)c[it++]=vec[l++];
while(r<=cnts)c[it++]=suf[r++];
vec[1]=c[1];
for(int i=2;i<it;++i){
vec[i]=c[i];
if(vec[i].first==vec[i-1].first)vec[i].second=vec[i-1].second;
}
pv=std::unique(vec+1,vec+it)-vec-1;
}
inline void check_prefix_with_vec(const int&v){
int len=233333;
for(int i=1;i<=cntp;++i)
while(pv&&(vec[pv].first|pre[i].first)>=v)
chkmin(len,pre[i].second-vec[pv--].second+1);
chkmin(ans,len);
}
}b[130];
int n,m,K;
int main(){
init();
n=readint(),m=readint();
for(int i=1;i<=n;++i)a[i]=readint();
n=bel(n)*siz;
K=n/siz;
for(int i=1;i<=K;++i)b[i].build((i-1)*siz+1,i*siz);
while(m--)
if(readint()==1){
const int pos=readint(),x=readint();
b[bel(pos)].modify(pos,x);
a[pos]=x;
}else{
ans=233333;
const int x=readint();
for(int i=1;i<=K;++i)
if(b[i].all>=x)chkmin(ans,b[i].getlen(x));
pv=0;
b[1].merge_suffix_to_vec();
for(int i=2;i<=K;++i){
b[i].check_prefix_with_vec(x);
for(int j=1;j<=pv;++j)vec[j].first|=b[i].all;
b[i].merge_suffix_to_vec();
}
printf("%d\n",(ans==233333)?-1:ans);
}
return 0;
}
[Ynoi2014]不归之人与望眼欲穿的人们的更多相关文章
- 题解 P5065 【[Ynoi2014]不归之人与望眼欲穿的人们】
出现了一篇跑得炒鸡慢的题解! noteskey 无 fuck 说,好像就是整个数列分块然后合并区间...什么的吧 对于每块内部就是算一下前缀信息.后缀信息(就是以 第一个点/最后一个点 为一个边界,不 ...
- [Ynoi2015]即便看不到未来
题目大意: 给定一个序列,每次询问,给出一个区间$[l,r]$. 设将区间内的元素去重后重排的数组为$p$,求$p$中长度为$1\sim 10$的极长值域连续段个数. 长度为$L$的极长值域连续段的定 ...
- [Ynoi2015]纵使日薄西山
题目大意: 给定一个序列,每次单点修改,然后进行询问. 定义一次操作为,选择一个位置$x$,将这个位置的数和左边.右边两个位置的数(不存在则忽略)各减去1,然后和0取max. 对序列中最大的位置进行一 ...
- [Ynoi2015]盼君勿忘
题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...
- [Ynoi2015]我回来了
题目大意: 给定一张无向无权图,每次给定若干个二元组\((x_i,y_i)\),定义点\(u\)满足条件,当且仅当存在\(i\),并满足\(dist(u,x_i)\leqslant y_i\)(\(d ...
- [Ynoi2015]此时此刻的光辉
题目大意: 给定一个序列,每次询问一段区间的数的乘积的约数个数. 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐 ...
- 不得不喷一下中控科技,ZKT,恶心的中控,售后技术和屎一样,半年不见人。
要做一个指纹考勤机和后台通信写入到mysql.在淘宝看了好多款,于是决定用指纹考勤机w6.卖家当时说支持二次开发,给我发的sdk.于是买了一台测试.机器来了开始测试,使用发的demo不能使用,于是去中 ...
- GitHub 实现多人协同提交代码并且权限分组管理
转载请标明出处: http://www.cnblogs.com/zhaoyanjun/p/5882784.html 出自[赵彦军博客] 2016-09-19 前言: 在上一篇文章中Android gi ...
- <转>请戒掉成功学和正能量,那是麻痹人的毒药 | 新知
非常不幸的是,这将是一场非常糟糕的演说.我不想骗你们,你们从我这里几乎什么也学不到.你们在离开的时候肯定会感到失望,你们的生活并不会得到改善. 更糟糕的是,你还会意识到生活的本质毫无意义,你的一切努力 ...
随机推荐
- (七)CAS 本地localhost调试,无法单点退出疑问
干活的时候要多思考-------- 题记 昨天下午接到任务把内容汇聚平台和分发平台加上统一认证登录,之前弄过CAS,想想这个过程也就是按部就班的事情.在两个系统中we ...
- [WebView学习之二]:使用Web Apps 支持不同分辨率屏
上一篇我们学习了(1.[WebView学习之中的一个]:Web Apps简单介绍),今天我们来继续学习. (博客地址:http://blog.csdn.net/developer_jiangqq),转 ...
- 【HDOJ 2255】奔小康赚大钱(KM算法)
[HDOJ 2255]奔小康赚大钱(KM算法) 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- HDU 5289 Assignment (ST算法区间最值+二分)
题目链接:pid=5289">http://acm.hdu.edu.cn/showproblem.php?pid=5289 题面: Assignment Time Limit: 400 ...
- 【c语言】字符串替换空格:请实现一个函数,把字符串中的每一个空格替换成“%20”
// 字符串替换空格:请实现一个函数,把字符串中的每一个空格替换成"%20". // 比如输入"we are happy.",则输出"we%20are ...
- spring:为javabean的集合对象注入属性值
spring:为JavaBean的集合对象注入属性值 在 spring 中可以对List.Set.Map 等集合进行配置,不过根据集合类型的不同,需要使用不同的标签配置对应相应的集合. 1.创建 Ts ...
- TCP打开文件传输(服务器端并发code)
#include <stdio.h>#include <stdlib.h>#include <arpa/inet.h>#include <sys/types. ...
- netty之ByteBuf详解
[ChannelPromise作用:可以设置success或failure 是为了通知ChannelFutureListener]Netty的数据处理API通过两个组件暴露——abstract cla ...
- C#WebForm里面aspx,ajax请求后台。。。
虽然WebForm里面有那些基本控件,后台CS里面也有许许多多的控件的方法.但是不见得有些标签不需要进行后台的访问,下面介绍一下三种aspx中访问后台的方式.. 第一种:WebMethod (静态方法 ...
- Android自定义开机和关机动画
Android自定义开机和关机动画 Android在开机的过程中,会经历三张图片,关于静态图的修改在我的这篇文章中有介绍到: Android开机图片替换 现在要介绍的是怎么用动画替换静态图片.开/关机 ...