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;
    }
  • 相关阅读:
    zoj 3279 线段树 OR 树状数组
    fzu 1962 树状数组 OR 线段树
    hdu 5057 块状链表
    hdu3487 Play with Chain
    bzoj 1588营业额统计(HNOI 2002)
    poj2823 Sliding Window
    poj2828 Buy Tickets
    poj2395 Out of Hay
    poj3667 Hotel
    poj1703 Lost Cows
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793264.html
Copyright © 2011-2022 走看看