题目大意:

给定一个序列,每次单点修改一个数,或给定$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. c语言char 和int的问题

    参考:http://www.cnblogs.com/dire/p/5222968.html 参考baidu: char和int的定义我是清楚的,现在有一个问题: 1.设A和B是int型,C是char型 ...

  2. pat解题报告【1082】

    1082. Read Number in Chinese (25) 时间限制   400 ms 内存限制   32000 kB 代码长度限制   16000 B 判题程序     Standard   ...

  3. Git是什么?

    Git是目前世界上最先进的分布式版本控制系统(没有之一). Git有什么特点?简单来说就是:高端大气上档次! 那什么是版本控制系统? 如果你用Microsoft Word写过长篇大论,那你一定有这样的 ...

  4. luogu2149 [SDOI2009] Dlaxia的路线

    题目大意 在一个无向图中,定义两个点s,t的最短路径子图为一个极大边集,对于该边集内的所有有向边e,总存在一条起点为s,终点为t且经过边e的路径,使得该路径长度为s到t的最短路径长度.现给出一个无向图 ...

  5. luogu1005 矩阵取数游戏

    题目大意 一个矩阵,每次从每一行的行首或行尾取一个数,每一行的价值为 取的数*2^当前取数的次数,每一次的价值为每一行的价值的和.求得到的价值的最大值. 思路 #include <cstdio& ...

  6. Codeforces--630H--Benches(组合数)

    H - Benches Crawling in process... Crawling failed Time Limit:500MS     Memory Limit:65536KB     64b ...

  7. Codeforces--630K--Indivisibility(容斥)

     K - Indivisibility Crawling in process... Crawling failed Time Limit:500MS     Memory Limit:65536 ...

  8. B2568 比特集合 树状数组

    啊啊啊,跳题坑死人.抽了一道国集的题,自己瞎编了一个算法,好像过不了而半途而废.转去看题解,发现用二维树状数组维护一下,偏移量我倒是想对了,但是维护的东西和我的完全不一样.还是有很大差距啊... 题解 ...

  9. Spell checker(串)

    http://poj.org/problem?id=1035 题意:给定一个单词判断其是否在字典中,若存在输出"%s is correct",否则判断该单词删掉一个字母,或增加一个 ...

  10. Appium + python - swipe滑屏操作实例

    方法一: from appium import webdriverfrom time import sleep descred_caps = { "platformName":&q ...