【洛谷】P4585 [FJOI2015]火星商店问题

题解

题目太丧,OJ太没有良心,我永远喜欢LOJ!
(TLE报成RE,垃圾洛谷,我永远喜欢LOJ)

好的,平复一下我debug了一上午崩溃的心态= =,写一写这道题的题解

把所有限制去掉,给出一个值,和一堆数种选一个异或起来求最大值,是一个经典的字典树问题,如果去掉了d的限制,我们类似主席树那样求一个可持久化字典树,利用前缀和就可以快速求得一个区间的字典树了,所以对于所有特殊商品,我们先用这些商品更新一下每一个询问

我们可以用线段树套可持久化trie树,然而空间很难办……
那么我们转为对每个线段树的区间,处理所有覆盖这个区间的询问就好了

对于所有后加的商品,按照商店编号排序
然后我们对于时间进行二分,二分到一个时间区间[L,R]

然后我们拿到这个区间里的商品建出一个trie树,然后找到所有询问里能完整覆盖整个时间区间的询问,更新这个询问的答案
再把询问分到左右区间去分治

代码

#include <bits/stdc++.h>
#define MAXN 100005
//#define ivorysi
#define enter putchar('\n')
#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;
}
posted @ 2018-06-07 11:32  sigongzi  阅读(160)  评论(0编辑  收藏  举报