题目描述
九条可怜有 n 盒拼图,每盒拼图都有若干拼图块,可以拼出许多矩形图案。
可是,可怜经常会弄丢拼图块,因此她需要将一些拼图送回厂家进行补块。可怜懒得将所有拼图拼好来检查完整性,仅当她的一盒拼图的拼图块数无法组成任何r 块×c 块的矩形图案(其中 r,c≥2),可怜才认为这盒拼图需要返厂补块。返厂补块需要的运费只和含有图块数最多的拼图有关。
可怜将 n 盒拼图从 1 到 n 编号。每次,可怜都想知道,如果从编号在[l,r] 区间内的拼图中选择 k 盒一定需要补块的拼图,拼图块数最多的拼图的拼图块数最少是多少。当然,可怜只是随口问问,并不会真的将这些拼图返厂,所以询问后所有拼图的块数都不会变化。
有时,可怜会发现自己数错了拼图的块数,并将第 x 盒拼图的拼图块数更新为 y。她希望你能即时回答这些询问。
输入格式
第一行两个整数 n,k,m,m 表示可怜询问和修改的数量和。
接下来一行 n 个正整数,第 i 个数表示第 i 盒拼图初始时的拼图块数。
接下来 m 行,每行 3 个数 opt,l,r。为了表明你在即时回答可怜的询问,真实的 opt,l,r 为输入的 opt,l,r 分别异或(XOR)lastans,其中 lastans 表示上一次询问的答案,若之前没有询问操作,则 lastans=0。
若 opt=1,则表示这是一次询问操作,询问的区间为[l,r]。
若 opt=2,则表示这是一次修改操作,把第 l 盒拼图的块数修改为 r。
输出格式
对于每个询问操作,输出一行一个整数,表示拼图块数最多的拼图的拼图块
数最少是多少。保证答案存在。
样例数据
3 1 3 5
4 5 6 7
1 1 3
7 7 2
4 4 6
3 2 3 7
4 5 7 5
1 1 3
5 4 2
6 6 4
数据范围
对于 30%的数据,n,m≤1000。
对于另 30%的数据,没有修改操作。
对于 100%的数据,1≤n,m,k≤200000,l,r 合法,所有拼图的块数在任何时刻是[4,1000000]区间中的整数。
如果对于 \(n\) ,有 \(n=r*c\),那么 \(n\) 就不需要返厂,也就说需要返厂的只有素数。
对于 \(opt=1\) ,需要在区间内选择 \(k\) 个数,使得最大的最小,返回最大的那个数。显然选择 \(k\) 个最小的数最优,于是问题变成了查询区间质数第 \(k\) 大,可以用主席树。
对于 \(opt=1\),单点修改,再结合1操作,想到树套树。
然而不管多么优秀的树套树都只能得到60分,数据还是太大?那么最奇妙的来了,我们发现不仅连操作的值被异或了(强制在线),opt也异或了?!opt只有1和2,一奇一偶。考虑对opt进行分类讨论,首先答案的值只可能是奇数(保证为[4,1000000]的素数),如果opt是奇数,又有 \((原opt)^lastans=现opt\),所以原opt一定是偶数,也就是2,同理如果opt为偶,那么原opt=1,最后把现opt异或上原opt就得到上一次操作的答案(???!!!)
Code:
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 1000003
#define INF 0x3f3f3f3f
int n,m,a[N],b[N],p[N],k,p_num;
bool mark[N];
template<class T>
inline void read(T &x){
x=0;char c=getchar();T flag=1;
while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
x*=flag;
}
inline void Pre(){
mark[1]=1;
for(int i=2;i<N;i++){
if(!mark[i])
p[++p_num]=i;
for(int j=1;j<=p_num&&i*p[j]<N;j++){
mark[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int main(){
freopen("jigsaw.in","r",stdin);
freopen("jigsaw.out","w",stdout);
Pre();
read(n),read(k),read(m);
int opt,l,r,ans=0;
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++){
read(opt),read(l),read(r);
if(opt&1){
l^=opt^2,r^=opt^2;
a[l]=r;
continue;
}
ans=opt^1;
if(ans!=3&&i!=1)
printf("%d\n",ans);
}
if(opt&1) return 0;
l^=opt^1,r^=opt^1;
for(int i=l;i<=r;i++)
if(!mark[a[i]])
b[++b[0]]=a[i];
sort(b+1,b+b[0]+1);
printf("%d\n",b[k]);
}