[FJOI2015]火星商店问题
题目
题解
下面称最大值为异或之后的最大值。
首先,我们可以将询问拆成俩部分:
- 从 \(L\sim R\) 的商店的特殊商品的最大值;
- 最近 \(D\) 天从 \(L\sim R\) 的商店的普通商店的最大值;
考虑分别建俩棵树:
- 第一颗:可持久化 \(\text{trie}\) 树,解决上面的第一个问题;
- 第二颗:线段树维护区间,节点 \([l,r]\) 表示商店 \(l\sim r\) 的修改历史,所谓的修改历史保存两个值:时间,修改之后的树根;
对于第一颗,在最开始输入特殊商品的价值时处理即可。
对于第二颗,用一般的线段树修改即可。
需要注意的是,我们要把所有的商店 \(s\) 涉及到的线段树节点全部修改。
代码实现的时候,将询问拆成多个区间(最多 \(log\) 个),然后将这些拆分之后的区间结合起来即可。
水完了一篇博客
#include<bits/stdc++.h>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T qread(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
#undef cg
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=100000;
const int logMAXN=16;
struct Node{int son[2],siz;}trie[MAXN*logMAXN+logMAXN*logMAXN*MAXN+5];
int tricnt=0;
int n,m,version;
vector< pii >exist[MAXN<<2|2];
inline int cpy_node(const int x){
trie[++tricnt]=trie[x];
++trie[tricnt].siz;
return tricnt;
}
inline int Insert(int x,const int num){
//在字典树里面插入 num
int ret=cpy_node(x);
int p=ret,f;
fep(i,logMAXN,0){
f=(num>>i)&1;
trie[p].son[f]=cpy_node(trie[x].son[f]);
p=trie[p].son[f],x=trie[x].son[f];
}
return ret;
}
int trie_query(const int x,int rt1,int rt2){
if(trie[rt1].siz==trie[rt2].siz)return 0;
int ret=0,f;
fep(i,logMAXN,0){
// printf("Now rt1 == %d, rt2 == %d\n",rt1,rt2);
f=(x>>i)&1;
// printf("And f == %d\n",f);
if(trie[trie[rt1].son[!f]].siz<trie[trie[rt2].son[!f]].siz){
// printf("Goto way !f == %d\n",!f);
ret+=(1<<i);
rt1=trie[rt1].son[!f],rt2=trie[rt2].son[!f];
}else rt1=trie[rt1].son[f],rt2=trie[rt2].son[f];
}
return ret;
}
#define lc (i<<1)
#define rc (i<<1|1)
#define mid ((l+r)>>1)
#define _lq lc,l,mid
#define _rq rc,mid+1,r
void buildtre(const int i=1,const int l=1,const int r=n){
exist[i].push_back(mp(0,0));
if(l==r)return;
buildtre(_lq),buildtre(_rq);
}
void modify(const int t,const int x,const int v,const int i=1,const int l=1,const int r=n){
int ret=Insert(exist[i].back().second,v);
exist[i].push_back(mp(t,ret));
if(l==r)return;
if(x<=mid)modify(t,x,v,_lq);
else modify(t,x,v,_rq);
}
int sgt_query(const int x,const int d,const int L,const int R,const int i=1,const int l=1,const int r=n){
if(L<=l && r<=R){
if(exist[i].back().first<=d)return 0;
int ql=0,qr=exist[i].size()-1,qmid,ans;
while(ql<=qr){
qmid=(ql+qr)>>1;
if(exist[i][qmid].first<=d)ql=qmid+1;
else ans=qmid,qr=qmid-1;
}//能够保证 ans > 0 (因为 i == 0 是 (0,0), 二分是不可能达到的)
return trie_query(x,exist[i][ans-1].second,exist[i].back().second);
}
int ret=0;
if(L<=mid)ret=sgt_query(x,d,L,R,_lq);
if(mid<R)ret=Max(ret,sgt_query(x,d,L,R,_rq));
return ret;
}
int rt[MAXN+5];//特殊商品的根
inline void Init(){
// cin>>n>>m;
n=qread(1),m=qread(1);
rep(i,1,n)rt[i]=Insert(rt[i-1],qread(1));
buildtre();
// rep(i,1,n)printf("rt[%d] == %d\n",i,rt[i]);
}
inline void Getoption(){
int opt,l,r,x,d,s,v;
while(m--){
// cin>>opt;
opt=qread(1);
if(opt==0){/*cin>>s>>v;*/
s=qread(1),v=qread(1);
modify(++version,s,v);
}else{/*cin>>l>>r>>x>>d;*/
l=qread(1),r=qread(1),x=qread(1),d=qread(1);
d=Max(0,version-d);
// printf("sgt_query == %d, trie_query == %d\n",sgt_query(x,d,l,r),trie_query(x,rt[l-1],rt[r]));
// cout<<Max(sgt_query(x,d,l,r),trie_query(x,rt[l-1],rt[r]))<<endl;
writc(Max(sgt_query(x,d,l,r),trie_query(x,rt[l-1],rt[r])),'\n');
}
// puts("After the option:");
// rep(i,1,n<<2){
// printf("When i == %d\n",i);
// for(auto it=exist[i].begin();it!=exist[i].end();++it)
// printf("%d %d\n",it->first,it->second);
// Endl;
// }
}
}
signed main(){
// freopen("mine.out","w",stdout);
Init();
Getoption();
return 0;
}