• BZOJ4137 & 洛谷4585:[FJOI2015]火星商店问题


    https://www.lydsy.com/JudgeOnline/problem.php?id=4137

    https://www.luogu.org/problemnew/show/P4585

    火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店。商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价。每个商店每天都有可能进一些新商品,其标价可能与已有商品相同。 
    火星人在这条商业街购物时,通常会逛这条商业街某一段路上的所有商店,譬如说商店编号在区间[L,R]中的商店,从中挑选1件自己最喜欢的商品。每个火星人对商品的喜好标准各不相同。通常每个火星人都有一个自己的喜好密码x。对每种标价为val的商品,喜好密码为x的火星人对这种商品的喜好程度与val异或x的值成正比。也就是说,val xor x的值越大,他就越喜欢该商品。每个火星人的购物卡在所有商店中只能购买最近d天内(含当天)进货的商品。另外,每个商店都有一种特殊商品不受进货日期限制,每位火星人在任何时刻都可以选择该特殊商品。每个商店中每种商品都能保证供应,不存在商品缺货的问题。 
    对于给定的按时间顺序排列的事件,计算每个购物的火星人的在本次购物活动中最喜欢的商品,即输出val xor x的最大值。这里所说的按时间顺序排列的事件是指以下2种事件: 
    事件0,用三个整数0,s,v,表示编号为s的商店在当日新进一种标价为v 的商品。 
    事件1,用5个整数1,L,R,x,d,表示一位火星人当日在编号为L到R的商店购买d天内的商品,该火星人的喜好密码为x。

    参考:https://blog.csdn.net/lvzelong2014/article/details/78688727

    继续练习线段树分治,虽然还是离不开题解但是已经知道拿什么分治了

    以及越来越深感线段树分治并不是线段树这一个事实了,开个专栏吧

    显然d的存在使得一些商品被“撤销”了,但是每个人的d都是不同的,我们就没法把商品放到线段树上。

    于是反其道而行之,把人扔到线段树上,把商品放到线段树上跑。

    然后每次询问异或最大值就是可持久化trie了。

    PS:时刻注意这里面有两个量:商品所在的商店,以及商品上货时间。不要搞混了。

    我们预先按照商店排序,然后根据当前的时间区间再重新分配即可(有点像整体二分)。

    #include<cmath>
    #include<queue>
    #include<vector>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    const int B=17;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct data{
        int l,r,x,L,R;
    }p[N];
    struct good{
        int s,v,t;
    }q[N],tmpl[N],tmpr[N];
    struct node{
        int son[2],sum;
    }tr[N*40];
    int n,m,pcnt,qcnt,ans[N],rt[N],num[N],pool;
    vector<int>seg[N*4];
    inline bool cmp(good a,good b){
        return a.s<b.s;
    }
    void insert(int y,int &x,int k,int now){
        tr[x=++pool]=tr[y];
        tr[x].sum++;
        if(now<0)return;
        bool p=k&(1<<now);
        insert(tr[y].son[p],tr[x].son[p],k,now-1);
        return;
    }
    int query(int nl,int nr,int k,int now){
        if(now<0)return 0;
        bool p=k&(1<<now);
        int delta=tr[tr[nr].son[p^1]].sum-tr[tr[nl].son[p^1]].sum;
        if(delta>0)return (1<<now)+query(tr[nl].son[p^1],tr[nr].son[p^1],k,now-1);
        else return query(tr[nl].son[p],tr[nr].son[p],k,now-1);
    }
    void add(int a,int l,int r,int l1,int r1,int x){
        if(r<l1||r1<l)return;
        if(l1<=l&&r<=r1){
            seg[a].push_back(x);return;
        }
        int mid=(l+r)>>1;
        add(a<<1,l,mid,l1,r1,x);add(a<<1|1,mid+1,r,l1,r1,x);
    }
    int find(int l,int r,int k){
        l--;
        while(l<r){
            int mid=(l+r+1)>>1;
            if(num[mid]<=k)l=mid;
            else r=mid-1;
        }
        return l;
    }
    void work(int a,int l,int r){
        pool=0;int cnt=0;
        for(int i=l;i<=r;i++){
            num[++cnt]=q[i].s;
            insert(rt[cnt-1],rt[cnt],q[i].v,B);
        }
        for(int i=0;i<seg[a].size();i++){
            int id=seg[a][i];
            int L=find(1,cnt,p[id].l-1),R=find(1,cnt,p[id].r);
            ans[id]=max(ans[id],query(rt[L],rt[R],p[id].x,B));
        }
    }
    void divide(int a,int l,int r,int l1,int r1){
        int mid=(l+r)>>1,len1=0,len2=0;
        work(a,l1,r1);
        for(int i=l1;i<=r1;i++){
            if(q[i].t<=mid)tmpl[len1++]=q[i];
            else tmpr[len2++]=q[i];
        }
        for(int i=0;i<len1;i++)q[i+l1]=tmpl[i];
        for(int i=0;i<len2;i++)q[i+l1+len1]=tmpr[i];
        if(l==r)return;
        divide(a<<1,l,mid,l1,l1+len1-1);
        divide(a<<1|1,mid+1,r,l1+len1,r1);
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],read(),B);
        for(int i=1;i<=m;i++){
            int op=read();
            if(!op){
                q[++qcnt].s=read();q[qcnt].v=read();
                q[qcnt].t=qcnt;
            }else{
                p[++pcnt].l=read();p[pcnt].r=read();
                p[pcnt].x=read();int d=read();
                p[pcnt].L=max(qcnt-d+1,1);p[pcnt].R=qcnt;
                ans[pcnt]=query(rt[p[pcnt].l-1],rt[p[pcnt].r],p[pcnt].x,B);
            }
        }
        for(int i=1;i<=pcnt;i++)add(1,1,qcnt,p[i].L,p[i].R,i);
        sort(q+1,q+qcnt+1,cmp);
        divide(1,1,qcnt,1,qcnt);
        for(int i=1;i<=pcnt;i++)printf("%d
    ",ans[i]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    5.1点击4个按钮显示相应的div
    4.1邮箱的全选,全不选,反选
    3.1点击3个按钮变宽变高变色
    2.4点击按钮填色
    2.3点击菜单显示div再点击就隐藏
    2.2 点击按钮改变文本框中的文字内容
    linux系统编程视频 百度网盘下载
    Linux网络编程视频 百度网盘
    Sage Crm 权限原理分析
    Sage CRM 平衡区域树结构
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9091014.html
Copyright © 2020-2023  润新知