• 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/+

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

  • 相关阅读:
    LeetCode Merge Two Sorted Lists 归并排序
    LeetCode Add Binary 两个二进制数相加
    LeetCode Climbing Stairs 爬楼梯
    034 Search for a Range 搜索范围
    033 Search in Rotated Sorted Array 搜索旋转排序数组
    032 Longest Valid Parentheses 最长有效括号
    031 Next Permutation 下一个排列
    030 Substring with Concatenation of All Words 与所有单词相关联的字串
    029 Divide Two Integers 两数相除
    028 Implement strStr() 实现 strStr()
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9091014.html
Copyright © 2020-2023  润新知