P4585 [FJOI2015] 火星商店问题

题意

\(n\) 个商店,编号 \(1\)\(n\),很多种商品,每个商品有个价值。
现在有集中操作:
0 s v 新开一天,并在这一天给编号为 \(s\) 的商店进货 \(v\)
1 l r x d 一个人来编号属于 \([l,r]\) 的商店买东西,设当前为第 \(now\) 天,那么祂可以买到 \([now-d+1,now]\) 天进的货,问祂能买到的物品中,价值异或 \(x\) 的最大值。
每个商店都有一个物品被神秘力量所眷顾,这个物品可以在任何时候买到,不受天数的限制,这些物品将会在开头给出祂们的价值。
所有输入的数在 \([0,10^5]\) 范围内。

思路

外层用一个线段树维护商店编号,里面用 \(Trie\) 维护。为了解决时间这个维度,\(Trie\) 上的每个节点记录到祂的最大时间,在 \(Trie\) 上游走时判断一下最晚的时间是否在合法区间内。可以把被神秘力量所眷顾的物品插入的时间设为无穷大,判断合法时不要管时间小于等于 \(now\),这是没有影响的。
时间复杂度 \(\mathcal O(n\log^2n)\)

代码

拿下最劣解。

/*
Luogu P4585 [FJOI2015] 火星商店问题
2026-04-22
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=100010;
int n,m,now;
class Trie{
private:
    struct node{int ch[2],ti;}t[maxn*17*17];
    int rt[maxn*17],cnt;
public:
    void insert(int id,int x,int ti){
        if(rt[id]==0) rt[id]=++cnt;
        int u=rt[id];t[u].ti=max(t[u].ti,ti);
        for(int i=17;i>=0;i--){
            int ch=!!(x&(1<<i));
            if(t[u].ch[ch]==0) t[u].ch[ch]=++cnt;
            u=t[u].ch[ch];
            t[u].ti=max(t[u].ti,ti);
        }
    }
    int query(int id,int x,int lt){
        int u=rt[id],ans=0;
        for(int i=17;i>=0;i--){
            int ch=!(x&(1<<i));
            if(t[t[u].ch[ch]].ti>=lt) u=t[u].ch[ch],ans|=(1<<i);
            else u=t[u].ch[!ch];
        }
        return ans;
    }
}Tr;
class Segment_Tree{
private:
    void insert(int u,int l,int r,int d,int z,int ti){
        if(l>d||r<d) return ;
        Tr.insert(u,z,ti);
        if(l==r) return ;
        int mid=l+r>>1;
        insert(u<<1,l,mid,d,z,ti),insert(u<<1|1,mid+1,r,d,z,ti);
    }
    int query(int u,int l,int r,int ll,int rr,int x,int lt){
        if(l>rr||r<ll) return 0;
        int ans=Tr.query(u,x,lt);
        if(ll<=l&&r<=rr) return ans;
        int mid=l+r>>1;
        return max({query(u<<1,l,mid,ll,rr,x,lt),query(u<<1|1,mid+1,r,ll,rr,x,lt)});
    }
public:
    void insert(int d,int z,int ti){insert(1,1,n,d,z,ti);}
    int query(int l,int r,int z,int lt){return query(1,1,n,l,r,z,lt);}
}sgt;
signed main(){
    read(n,m);
    for(int i=1;i<=n;i++){
        int x;read(x);
        sgt.insert(i,x,20120515);
    }
    int now=0;
    for(int i=1;i<=m;i++){
        int op,s,v,l,r,x,d;read(op);
        if(op){
            read(l,r,x,d);
            write(sgt.query(l,r,x,now-d+1));write("\n");
        }
        else{
            read(s,v);
            now++;
            sgt.insert(s,v,now);
        }
    }
    return 0;
}
posted @ 2026-04-22 21:12  Link-Cut_Trees  阅读(5)  评论(0)    收藏  举报