题解
题目太丧,OJ太没有良心,我永远喜欢LOJ!
(TLE报成RE,垃圾洛谷,我永远喜欢LOJ)
好的,平复一下我debug了一上午崩溃的心态= =,写一写这道题的题解
把所有限制去掉,给出一个值,和一堆数种选一个异或起来求最大值,是一个经典的字典树问题,如果去掉了d的限制,我们类似主席树那样求一个可持久化字典树,利用前缀和就可以快速求得一个区间的字典树了,所以对于所有特殊商品,我们先用这些商品更新一下每一个询问
我们可以用线段树套可持久化trie树,然而空间很难办……
那么我们转为对每个线段树的区间,处理所有覆盖这个区间的询问就好了
对于所有后加的商品,按照商店编号排序
然后我们对于时间进行二分,二分到一个时间区间[L,R]
然后我们拿到这个区间里的商品建出一个trie树,然后找到所有询问里能完整覆盖整个时间区间的询问,更新这个询问的答案
再把询问分到左右区间去分治
代码
#include <bits/stdc++.h>
#define MAXN 100005
//#define ivorysi
#define enter putchar('
')
#define space putchar(' ')
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
int a[MAXN];
int ch[MAXN * 40][2],Ncnt,rt[MAXN * 2],siz[MAXN * 40],ans[MAXN * 2],cntq,cnti,D,num[MAXN],MK;
struct qry_node {
int L,R,sl,sr,val,id;
}qry[MAXN],tmp[MAXN];
struct change_node {
int s,t,v;
friend bool operator < (const change_node &a,const change_node &b) {
return a.s < b.s;
}
}item[MAXN],DO[MAXN];
void Insert(const int x,int &y,int v,int d) {
y = ++Ncnt;
ch[y][0] = ch[x][0],ch[y][1] = ch[x][1];
siz[y] = siz[x];
++siz[y];
if(d < 0) return;
if(v >> d & 1) Insert(ch[x][1],ch[y][1],v,d - 1);
else Insert(ch[x][0],ch[y][0],v,d - 1);
}
int query(int x,int L,int R) {
L = rt[L];R = rt[R];
int res = 0;
for(int i = 16 ; i >= 0 ; --i) {
if(x >> i & 1) {
if(siz[ch[R][0]] > siz[ch[L][0]]) res |= 1 << i,R = ch[R][0],L = ch[L][0];
else R = ch[R][1],L = ch[L][1];
}
else {
if(siz[ch[R][1]] > siz[ch[L][1]]) res |= 1 << i,R = ch[R][1],L = ch[L][1];
else R = ch[R][0],L = ch[L][0];
}
}
return res;
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) read(a[i]);
for(int i = 1 ; i <= N ; ++i) {
Insert(rt[i - 1],rt[i],a[i],16);
}
int op,l,r,x,d;
for(int i = 1 ; i <= M ; ++i) {
read(op);
if(op == 1) {
read(l);read(r);read(x);read(d);
ans[i] = query(x,l - 1,r);
if(D != 0 && d != 0) {
qry[++cntq] = (qry_node){l,r,max(1,D - d + 1),D,x,i};
}
}
else {
++D;
ans[i] = -1;
read(x);read(d);
item[++cnti] = (change_node){x,D,d};
}
}
sort(item + 1,item + cnti + 1);
}
void work(int l,int r) {
Ncnt = 0;
MK = 0;
num[0] = 0;
for(int i = l ; i <= r ; ++i){
++MK;
Insert(rt[MK - 1],rt[MK],item[i].v,16);
num[MK] = item[i].s;
}
}
int find(int x) {
int l = 0,r = MK;
while(l < r) {
int mid = (l + r + 1) >> 1;
if(num[mid] <= x) l = mid;
else r = mid - 1;
}
return l;
}
void Solve(int cl,int cr,int tl,int tr,int tot) {
if(!tot || cr < cl) return;
work(cl,cr);
for(int i = 1 ; i <= tot ; ++i) {
if(qry[i].sl <= tl && qry[i].sr >= tr) {
int l = find(qry[i].L - 1);
int r = find(qry[i].R);
ans[qry[i].id] = max(ans[qry[i].id],query(qry[i].val,l,r));
}
}
int MID = (tl + tr) >> 1;
if(tl == tr) return;
int p = 0,q = tot;
for(int i = 1 ; i <= tot ; ++i) {
if(qry[i].sl <= tl && qry[i].sr >= tr) tmp[q--] = qry[i];
else if(qry[i].sl <= MID) tmp[++p] = qry[i];
else tmp[q--] = qry[i];
}
for(int i = 1 ; i <= tot ; ++i) qry[i] = tmp[i];
int mk = cl,c;
for(int i = cl ; i <= cr ; ++i) if(item[i].t <= MID) DO[mk++] = item[i];
c = mk - cl;
for(int i = cl ; i <= cr ; ++i) if(item[i].t > MID) DO[mk++] = item[i];
for(int i = cl ; i <= cr ; ++i) item[i] = DO[i];
Solve(cl,cl + c - 1,tl,MID,p);
p = 0,q = tot;
for(int i = 1 ; i <= tot; ++i) {
if(qry[i].sl <= tl && qry[i].sr >= tr) tmp[q--] = qry[i];
else if(qry[i].sr > MID) tmp[++p] = qry[i];
else tmp[q--] = qry[i];
}
for(int i = 1 ; i <= tot ; ++i) qry[i] = tmp[i];
Solve(cl + c,cr,MID + 1,tr,p);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve(1,cnti,1,D,cntq);
for(int i = 1 ; i <= M ; ++i) {
if(ans[i] != -1) out(ans[i]),enter;
}
//out(clock());enter;
return 0;
}