zoukankan      html  css  js  c++  java
  • 【BZOJ4137】火星商店问题(FJOI2015)-线段树分治+可持久化trie

    测试地址:火星商店问题
    题目大意:n个商店,每个商店都有一个特殊商品,每个人在任何时间都可以买。第一天可能没有进货,有若干次询问,而之后的每天,都有一次进货和若干次询问,每次进货都是某个商店进了某个编号的货,每次询问都是询问在编号为lr的商店中,在d天内进的货的编号异或x的最大值。
    做法:本题需要用到线段树分治+可持久化trie。
    对于特殊商品,直接用可持久化trie就可以了。而对于其他的部分,可以很容易看出线段树套可持久化trie的做法,线段树对时间排序,一棵可持久化trie内不同棵trie按位置从小到大排序,trie内显然就是存商品的编号了。但直接这样套的话,空间一定会爆炸,因此我们考虑把询问离线,然后模拟在线段树上分治的过程。
    对于每个询问,会在线段树上分成O(logn)个节点,因此我们只需要在处理到某一个节点时,对这个节点表示的时间区间内进行的修改操作建可持久化trie,然后对每个有分配到当前节点的询问,用O(logn)的复杂度进行询问就行了,因此修改和询问的时间复杂度都是O(nlog2n)。并且,因为在任何时刻我们都只建一棵可持久化trie,空间问题就迎刃而解了。于是我们就解决了这一题。
    (这一道题说是“线段树分治”让我非常疑惑,线段树本身是序列分治过程的一种表示,因此在线段树上的任何问题其实都可算作分治,这道题主要特殊在从树套树通过对询问离线变换成一维分治+一维数据结构的思路,但鉴于网上诸多大佬都把这称作线段树分治,我也就这么叫吧)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,day,rt[100010]={0},totp,totmd,totq;
    int ch[2000010][2]={0},sum[2000010]={0};
    int ans[100010],id[100010];
    struct Modify {int tim,pos,x;} md[200010],tmpl[100010],tmpr[100010];
    struct Query {int l,r,x,tl,tr;} q[100010];
    
    void add(int v,int last,int x)
    {
        sum[v]=sum[last]+1;
        for(int i=16;i>=0;i--)
        {
            bool f=(x&(1<<i));
            ch[v][f]=++totp;
            ch[v][!f]=ch[last][!f];
            v=ch[v][f];
            last=ch[last][f];
            sum[v]=sum[last]+1;
        }
    }
    
    int query(int v,int last,int x)
    {
        int ans=0;
        for(int i=16;i>=0;i--)
        {
            ans<<=1;
            bool f=(x&(1<<i));
            f=!f;
            if (sum[ch[v][f]]-sum[ch[last][f]]>0) ans++;
            else f=!f;
            v=ch[v][f];
            last=ch[last][f];
        }
        return ans;
    }
    
    int lower(int ml,int l,int r,int x)
    {
        if (md[l].pos>x) return 0;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if (md[mid+1].pos<=x) l=mid+1;
            else r=mid;
        }
        return l-ml+1;
    }
    
    void work(int ml,int mr,int qr)
    {
        totp=0;
        int tottim=0;
        for(int i=ml;i<=mr;i++)
        {
            rt[++tottim]=++totp;
            add(rt[tottim],rt[tottim-1],md[i].x);
        }
        for(int i=1;i<=qr;i++)
        {
            int L=lower(ml,ml,mr,q[id[i]].l-1);
            int R=lower(ml,ml,mr,q[id[i]].r);
            ans[id[i]]=max(ans[id[i]],query(rt[R],rt[L],q[id[i]].x));
        }
    }
    
    void solve(int ml,int mr,int tl,int tr,int tp)
    {
        if (ml>mr||!tp) return;
        int tot=0;
        for(int i=1;i<=tp;i++)
            if (q[id[i]].tl<=tl&&tr<=q[id[i]].tr&&q[id[i]].tl<=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(int i=ml;i<=mr;i++)
        {
            if (md[i].tim<=mid) tmpl[++lt]=md[i];
            else tmpr[++rt]=md[i];
        }
        for(int i=1;i<=lt;i++) md[ml+i-1]=tmpl[i];
        for(int i=1;i<=rt;i++) md[ml+lt+i-1]=tmpr[i];
    
        tot=0;
        for(int 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]);
        }
        solve(ml,ml+lt-1,tl,mid,tot);
        tot=0;
        for(int 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]);
        }
        solve(ml+lt,mr,mid+1,tr,tot);
    }
    
    bool cmp(Modify a,Modify b)
    {
        return a.pos<b.pos;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        day=0;
        totmd=totq=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&md[++totmd].x);
            md[totmd].tim=0;
            md[totmd].pos=i;
        }
    
        int st=totmd;
        for(int i=1;i<=m;i++)
        {
            int op;
            scanf("%d",&op); 
            if (!op)
            {
                day++;
                md[++totmd].tim=day;
                scanf("%d%d",&md[totmd].pos,&md[totmd].x);
            }
            else
            {
                ++totq;
                id[totq]=totq;
                scanf("%d%d%d%d",&q[totq].l,&q[totq].r,&q[totq].x,&q[totq].tl);
                q[totq].tl=max(day-q[totq].tl+1,1);
                q[totq].tr=day;
            }
        }
    
        sort(md+1,md+st+1,cmp);
        sort(md+st+1,md+totmd+1,cmp);
        work(1,st,totq);
        solve(st+1,totmd,1,day,totq);
        for(int i=1;i<=totq;i++)
            printf("%d
    ",ans[i]); 
    
        return 0;
    }
  • 相关阅读:
    SSM框架整合步骤
    Spring-data-jpa
    allure定制报告
    pytest常用选项
    staticmethod&classmethod&property
    __slot__
    python的参数传递
    闭包和装饰器
    内置高阶函数
    str
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793264.html
Copyright © 2011-2022 走看看