[BZOJ4137][FJOI2015]火星商店问题

luogu

description

有若干个\(\mbox{vector}\),支持单点\(\mbox{push_back}\),以及询问最近\(d\)\(\mbox{push_back}\)操作中在区间\([l,r]\)内的数与\(k\)的异或最大值。
所有数\(\le10^5\)

sol

开一棵线段树,每个节点是一棵\(\mbox{Trie}\)树,这样就可以查异或最大值了。
怎么处理时间的限制呢?在\(\mbox{Trie}\)树的每个节点维护一下这个节点的最新更新时间,查询的时候如果这个最新更新时间大于一个和\(d\)有关的限制就表示可以往这个子树走,否则就不行。

然后这样子据说会\(MLE\)
所以就把所有修改个询问都挂链挂到每个线段树的节点上,再离线线段树分治,这样空间复杂度就可以优化到\(O(n\log n)\)

code

我不管反正我就是写在线做法。
洛谷过了,然后\(BZ\)的数据本地测过了。别的我不管qwq。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e5+5;
int n,m,tim,ch[2][N*100],val[N*100],R[N],rt[N<<2],tot,ans;
void mdf1(int &x,int p,int dep){
    ++tot;ch[0][tot]=ch[0][x];ch[1][tot]=ch[1][x];
    val[tot]=val[x]+1;x=tot;if (!~dep) return;
    mdf1(ch[(p>>dep)&1][x],p,dep-1);
}
int qry1(int x,int y,int p,int dep){
    if (!~dep) return 0;int c=~(p>>dep)&1;
    if (val[ch[c][x]]-val[ch[c][y]]) return qry1(ch[c][x],ch[c][y],p,dep-1)|(1<<dep);
    c^=1;return qry1(ch[c][x],ch[c][y],p,dep-1);
}
void mdf2(int &x,int p,int dep,int t){
    if (!x) x=++tot;val[x]=t;if (!~dep) return;
    mdf2(ch[(p>>dep)&1][x],p,dep-1,t);
}
int qry2(int x,int p,int dep,int t){
    if (!~dep) return 0;int c=~(p>>dep)&1;
    if (val[ch[c][x]]>t) return qry2(ch[c][x],p,dep-1,t)|(1<<dep);
    c^=1;return qry2(ch[c][x],p,dep-1,t);
}
void modify(int x,int l,int r,int p,int v,int t){
    mdf2(rt[x],v,16,t);
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) modify(x<<1,l,mid,p,v,t);
    else modify(x<<1|1,mid+1,r,p,v,t);
}
void query(int x,int l,int r,int ql,int qr,int v,int t){
    if (l>=ql&&r<=qr) {ans=max(ans,qry2(rt[x],v,16,t));return;}
    int mid=l+r>>1;
    if (ql<=mid) query(x<<1,l,mid,ql,qr,v,t);
    if (qr>mid) query(x<<1|1,mid+1,r,ql,qr,v,t);
}
int main(){
    n=gi();m=gi();
    for (int i=1;i<=n;++i) mdf1(R[i]=R[i-1],gi(),16);
    for (int i=1;i<=m;++i)
        if (gi()){
            int l=gi(),r=gi(),v=gi(),d=gi();
            ans=qry1(R[r],R[l-1],v,16);
            query(1,1,n,l,r,v,tim-d);printf("%d\n",ans);
        }else{
            int p=gi(),v=gi();
            modify(1,1,n,p,v,++tim);
        }
    return 0;
}

转载于:https://www.cnblogs.com/zhoushuyu/p/9385869.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值