[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;
}
posted @ 2020-05-18 22:01  Arextre  阅读(129)  评论(0编辑  收藏  举报