zoukankan      html  css  js  c++  java
  • bzoj4137[FJOI2015]火星商店问题

    分析:

    首先,一看到求val xor x最大,我们就应该想到可持久化Trie,(详见P4585),这样,当我们询问 L,RL,RL,R 之间的最大异或值时,就直接套用可持久化Trie就行了,这样空间这一维就可以处理了。如果全是特殊商品的话,这个问题就解决了,但还有时间这一维啊,怎么办?(把出题人吊起来打一顿,让他改数据

    时间怎么办?

    首先,每个火星人能够买的商品的进货时间应该是在一段时间区间内(对普通商品而言),那么只有在这个区间内的商品才能被该火星人买,即对该次询问做贡献,而如果我们把商品看成一个,那么某次询问就是对一段区间上所有的点做一次询问,那么,我们会发现:

    这个可以用线段树维护

    如果我们在线处理的话,就会重复运算很多次,就可能会 $TLE$ ,其实我也没试过,于是,我们就要引出这题正解了:

    线段树分治

    所谓线段树分治,就是把某一段区间用线段树的方法分成很多段子区间,再把修改和询问一起放在线段树上,然后再统一一起处理一遍,这样做的好处在于,可以省掉许多重复计算,提高效率。

    好了,那么对于这题而言,只要用线段树的方法处理区间询问和单点修改就行了。也就是对于当前区间 $[L,R]$先把完全包含它的所有询问用这一区间内的(商品)更新,再把在左/右区间的点和与左/右区间有交集且没有用该区间更新过的用的询问一起往下递归处理,直到没有询问传递下来为止。
    具体看代码吧

    Code

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<iostream>
    #include<queue>
    #include<iomanip>
    #include<algorithm>
    using namespace std;
    const int N=100010;
    
    int n,m,day,ans[N];
    struct node
    {
        int time,val,pos;
    }a[N*2];
    int totm;
    struct que
    {
        int l,r,tl,tr,x;
    }q[N*2];
    int totq,id[N],cnt;
    int ch[N<<5][2],root[N],sum[N<<5],totp;
    node tmpl[N*2],tmpr[N*2];
    
    bool cmp(const node &a,const node &b)
    {
        return a.pos<b.pos;
    }
    
    void add(int x,int x1,int val)//可持久化trie
    {
        int i,j;
        sum[x]=sum[x1]+1;
        for(i=16;i>=0;i--)
        {
            bool f=(val&(1<<i));
            ch[x][!f]=ch[x1][!f];
            x1=ch[x1][f];
            x=ch[x][f]=++cnt;
            sum[x]=sum[x1]+1;
        }
    }
    
    int quer(int x,int x1,int val)//可持久化trie
    {
        int ans=0,i;
        for(i=16;i>=0;i--)
        {
            ans<<=1;
            bool f=(val&(1<<i));
            if(ch[x1][!f]>ch[x][!f]) ans++;
            else f=!f;
            x=ch[x][!f];x1=ch[x1][!f];
        }
        return ans;
    }
    
    int find(int l,int r,int x)
    {
        int ml=l;
        if(a[l].pos>x) return 0;
        while(l<r)
        {
            int mid=l+r>>1;
            if(a[mid+1].pos<=x) l=mid+1;
            else r=mid;
        }
        return l-ml+1;
    }
    
    void work(int ml,int mr,int qr)//用可持久化trie更新询问
    {
        totp=0;cnt=0;
        int i,j,k;
        for(i=ml;i<=mr;i++)
        {
            totp++;cnt++;
            root[totp]=cnt;
            add(root[totp],root[totp-1],a[i].val);
        }
        for(i=1;i<=qr;i++)
        {
            int l=find(ml,mr,q[id[i]].l-1);
            int r=find(ml,mr,q[id[i]].r);
            ans[id[i]]=max(ans[id[i]],quer(root[l],root[r],q[id[i]].x));
        }
    }
    
    void slove(int ml,int mr,int tl,int tr,int tp)
    {
        if(ml>mr||tp==0) return;
        int tot=0,i,j;
        for(i=1;i<=tp;i++)
            if(q[id[i]].tl<=tl&&tr<=q[id[i]].tr)
                swap(id[i],id[++tot]);
        work(ml,mr,tot);
        if(tl==tr) return;
        int mid=tl+tr>>1,lt=0,rt=0;
        for(i=ml;i<=mr;i++)
        {
            if(a[i].time<=mid) tmpl[++lt]=a[i];
            else tmpr[++rt]=a[i];
        }
        for(i=1;i<=lt;i++) a[ml+i-1]=tmpl[i];
        for(i=1;i<=rt;i++) a[ml+lt+i-1]=tmpr[i];
        tot=0;
        for(i=1;i<=tp;i++) 
        {
            if(q[id[i]].tl<=tl&&tr<=q[id[i]].tr) continue;
            if(q[id[i]].tl<=mid) swap(id[i],id[++tot]);
        }
        slove(ml,ml+lt-1,tl,mid,tot);
        tot=0;
        for(i=1;i<=tp;i++) 
        {
            if(q[id[i]].tl<=tl&&tr<=q[id[i]].tr) continue;
            if(q[id[i]].tr>mid) swap(id[i],id[++tot]);
        }
        slove(ml+lt,mr,mid+1,tr,tot);
    }
    
    int main()
    {
        int i,j,op,k,d;
        totq=day=0;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i].val);
            a[i].pos=i;a[i].time=0;
        }
        int spt;
        spt=totm=n;
        for(i=1;i<=m;i++)
        {
            scanf("%d",&op);
            if(op==0)
            {
                day++;a[++totm].time=day;
                scanf("%d%d",&a[totm].pos,&a[totm].val);
            }
            else
            {
                totq++;
                id[totq]=totq;
                scanf("%d%d%d%d",&q[totq].l,&q[totq].r,&q[totq].x,&d);
                q[totq].tr=day;q[totq].tl=max(day-d+1,1);
            }
        }
        sort(a+spt+1,a+totm+1,cmp);
        work(1,spt,totq);//特殊商品单独处理
        slove(spt+1,totm,1,day,totq);//线段树分治
        for(i=1;i<=totq;i++) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    主攻ASP.NET MVC4.0之重生:Asp.Net MVC WebApi OData
    跨平台移动开发 Android使用JPush推送消息
    跨平台移动开发 手机上使用Iscroll.Js的Banner
    主攻ASP.NET MVC4.0之重生:MVC Controller修改Controller.tt模版,自动添加版本注释信息
    正则表达式 获取字符串内提取图片URL字符串
    学习C#之旅 冒泡排序,选择排序,插入排序,希尔排序[资料收集]
    主攻ASP.NET MVC4.0之重生:使用反射获取Controller的ActionResult
    跨平台移动开发_PhoneGap 使用Accelerometer 加速器
    跨平台移动开发_PhoneGap 使用Geolocation基于所在地理位置坐标调用百度地图API
    跨平台移动开发_PhoneGap 警告,通知,鸣叫,振动4 种通知类型
  • 原文地址:https://www.cnblogs.com/lyh0313Blog/p/10778242.html
Copyright © 2011-2022 走看看