题目大意:

给定一个序列,每次单点修改一个数,或给定$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]不归之人与望眼欲穿的人们的更多相关文章

  1. 题解 P5065 【[Ynoi2014]不归之人与望眼欲穿的人们】

    出现了一篇跑得炒鸡慢的题解! noteskey 无 fuck 说,好像就是整个数列分块然后合并区间...什么的吧 对于每块内部就是算一下前缀信息.后缀信息(就是以 第一个点/最后一个点 为一个边界,不 ...

  2. [Ynoi2015]即便看不到未来

    题目大意: 给定一个序列,每次询问,给出一个区间$[l,r]$. 设将区间内的元素去重后重排的数组为$p$,求$p$中长度为$1\sim 10$的极长值域连续段个数. 长度为$L$的极长值域连续段的定 ...

  3. [Ynoi2015]纵使日薄西山

    题目大意: 给定一个序列,每次单点修改,然后进行询问. 定义一次操作为,选择一个位置$x$,将这个位置的数和左边.右边两个位置的数(不存在则忽略)各减去1,然后和0取max. 对序列中最大的位置进行一 ...

  4. [Ynoi2015]盼君勿忘

    题目大意: 给定一个序列,每次查询一个区间\([l,r]\)中所有子序列分别去重后的和\(\bmod p\)(每次询问模数不同). 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后 ...

  5. [Ynoi2015]我回来了

    题目大意: 给定一张无向无权图,每次给定若干个二元组\((x_i,y_i)\),定义点\(u\)满足条件,当且仅当存在\(i\),并满足\(dist(u,x_i)\leqslant y_i\)(\(d ...

  6. [Ynoi2015]此时此刻的光辉

    题目大意: 给定一个序列,每次询问一段区间的数的乘积的约数个数. 解题思路: 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐 ...

  7. 不得不喷一下中控科技,ZKT,恶心的中控,售后技术和屎一样,半年不见人。

    要做一个指纹考勤机和后台通信写入到mysql.在淘宝看了好多款,于是决定用指纹考勤机w6.卖家当时说支持二次开发,给我发的sdk.于是买了一台测试.机器来了开始测试,使用发的demo不能使用,于是去中 ...

  8. GitHub 实现多人协同提交代码并且权限分组管理

    转载请标明出处: http://www.cnblogs.com/zhaoyanjun/p/5882784.html 出自[赵彦军博客] 2016-09-19 前言: 在上一篇文章中Android gi ...

  9. <转>请戒掉成功学和正能量,那是麻痹人的毒药 | 新知

    非常不幸的是,这将是一场非常糟糕的演说.我不想骗你们,你们从我这里几乎什么也学不到.你们在离开的时候肯定会感到失望,你们的生活并不会得到改善. 更糟糕的是,你还会意识到生活的本质毫无意义,你的一切努力 ...

随机推荐

  1. jQuery toast message 地址 使用

    jQuery toast message 地址 使用 https://github.com/akquinet/jquery-toastmessage-plugin/wiki

  2. Verilog堵塞赋值与非堵塞赋值

    verilog设计进阶 时间:2014年5月6日星期二 主要收获: 1.堵塞赋值与非堵塞赋值: 2.代码測试: 3.组合逻辑电路和时序逻辑电路. 堵塞赋值与非堵塞赋值: 1.堵塞赋值"=&q ...

  3. PHP中JSON的应用

    文章来源:PHP开发学习门户 地址:  http://www.phpthinking.com/archives/513 互联网的今天,AJAX已经不是什么陌生的词汇了.说起AJAX,可能会马上想起因R ...

  4. 详略。。设计模式1——单例。。。。studying

    设计模式1--单例 解决:保证了一个类在内存中仅仅能有一个对象. 怎么做才干保证这个对象是唯一的呢? 思路: 1.假设其它程序可以任意用new创建该类对象,那么就无法控制个数.因此,不让其它程序用ne ...

  5. Skyline V6.6.1安装文件下载及使用

     1.下载地址:http://www.skylineglobe.com/skylineglobe/corporate/download/DownloadCenter.aspx 2.安装指南:   ...

  6. tolua reference

    Using Lua API and tag method facilities, tolua maps C/C++ constants, external variables, functions, ...

  7. Android 重写onBackPressed()方法 遇到的问题

    1.resultCode的值一直为0 问题描述:AActivity调用startActivityForResult()方法,启动BActivity,然后在BActivity的onBackPressed ...

  8. linux中两个缓冲区

    不同于Windows,Linux系统里存在两个剪切板:一个叫做选择缓冲区(X11 selection buffer),另一个才是剪切板(clipboard). 01)选择缓冲区(缓冲内容在其他位置可用 ...

  9. Linux framebuffer显示bmp图片【转】

    本文转载自:http://blog.csdn.net/luxiaoxun/article/details/7622988 framebuffer简介 帧缓冲(framebuffer)是Linux为显示 ...

  10. Too-Java:Intellij Idea

    ylbtech-Too-Java:Intellij Idea IDEA 全称 IntelliJ IDEA,是java编程语言开发的集成环境.IntelliJ在业界被公认为最好的java开发工具之一,尤 ...