可持久化trie+線段樹分治題 火星商店

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

做法:首先觀察到每個人能買的商品是一段區間,考慮將這個區間拆成log段存在線段樹節點上(開vector),這樣就可以考慮對線段樹每個節點所代表的商品區間建一棵可持久化trie,然後更新它這個節點上的所有詢問,這樣做其實算是一種整體二分,複雜度n*log^2

(做這題第一發wa了,調了1個小時發現空間開小了mmp,原來trie裏插入一個x位的數是要開x+1個點的...平時這麼開沒關係是因爲trie裏很多節點是共用的,而可持久化trie是嚴格開滿的就gg了......)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100,lim=1<<17;

template<class T>
void rd(T &x)
{
    char c=getchar();x=0;bool f=0;
    while(!isdigit(c))f|=(c=='-'),c=getchar();
    while(isdigit(c))x=x*10+c-48,c=getchar();
    if(f)x=-x;
}
void Mx(int &x,int y)
{x=max(x,y);}

struct Trie{
    int nxt[20*N][2],sz[20*N],tot,edit[N];
    void clear(){tot=0,nxt[0][0]=nxt[0][1]=0,sz[0]=0,edit[0]=0;}
    int ins(int bf,int x,int mo)
    {
        int nw=++tot;
        sz[nw]=sz[bf]+1;
        if(!mo)return nw;
        nxt[nw][0]=nxt[bf][0],nxt[nw][1]=nxt[bf][1];
        if(x&mo)nxt[nw][1]=ins(nxt[bf][1],x,mo>>1);
        else nxt[nw][0]=ins(nxt[bf][0],x,mo>>1);
        return nw;
    }
    int qry(int fr,int to,int x,int mo)
    {
        if(!mo)return 0;
        int op=(x&mo)?0:1;
        if(sz[nxt[to][op]]-sz[nxt[fr][op]]>=1)return mo+qry(nxt[fr][op],nxt[to][op],x,mo>>1);
        else return qry(nxt[fr][op^1],nxt[to][op^1],x,mo>>1);
    }
    int ask(int fr,int to,int x)
    {return qry(edit[fr],edit[to],x,lim);}
    void insert(int id,int x)
    {edit[id]=ins(edit[id],x,lim);}
}trie;
struct pp{
    int l,r,L,R,x;
    pp(){};
    pp(int l,int r,int L,int R,int x):l(l),r(r),L(L),R(R),x(x){};
}qry[N];int qnum=0;
struct th{
    int tim,wh,val;
    th(){};
    th(int tim,int wh,int val):tim(tim),wh(wh),val(val){};
}buy[N],tax1[N],tax2[N];
int n,m,tim=0,ans[N],hav[N],hnum;
vector<int>seg[N<<2];


bool cmp(th x,th y)
{return x.wh<y.wh;}


void seg_ins(int l,int r,int k,int L,int R,int val)
{
    if(L>R)return;
    if(L<=l&&r<=R)seg[k].push_back(val);
    else
    {
        int mid=(l+r)>>1;
        if(L<=mid)seg_ins(l,mid,k<<1,L,R,val);
        if(R>mid)seg_ins(mid+1,r,k<<1|1,L,R,val);
    }
}

void sol(int l,int r,int L,int R,int k)
{
    if(L>R)return;
    int nw=0;
    trie.clear(),hnum=0;
    for(int i=L;i<=R;i++)
    {
        ++nw,hav[++hnum]=buy[i].wh,trie.edit[nw]=trie.edit[nw-1];
        trie.insert(nw,buy[i].val);
    }
    for(int i=0,lps,rps;i<seg[k].size();i++)
    {
        nw=seg[k][i];
        lps=upper_bound(hav+1,hav+hnum+1,qry[nw].l-1)-hav-1;
        rps=upper_bound(hav+1,hav+hnum+1,qry[nw].r)-hav-1;
        Mx(ans[nw],trie.ask(lps,rps,qry[nw].x));
    }
    if(l==r)return;
    int tnum1=0,tnum2=0,mid=(l+r)>>1;
    for(int i=L;i<=R;i++)
    {
        if(buy[i].tim<=mid)tax1[++tnum1]=buy[i];
        else tax2[++tnum2]=buy[i];
    }
    for(int i=1;i<=tnum1+tnum2;i++)
    {
        if(i<=tnum1)buy[L+i-1]=tax1[i];
        else buy[L+i-1]=tax2[i-tnum1];
    }
    sol(l,mid,L,L+tnum1-1,k<<1);
    sol(mid+1,r,L+tnum1,R,k<<1|1);
}

int main()
{
    rd(n),rd(m);
    trie.clear();
    for(int i=1,tmp;i<=n;i++)
        rd(tmp),trie.edit[i]=trie.edit[i-1],trie.insert(i,tmp);
    int op,x,y,d,l,r;
    for(int i=1;i<=m;i++)
    {
        rd(op);
        if(op)
        {
            rd(l),rd(r),rd(x),rd(d);
            qry[++qnum]=pp(l,r,max(1,tim-d+1),tim,x);
            ans[qnum]=trie.ask(l-1,r,x);
        }
        else
        {
            rd(x),rd(y),++tim;
            buy[tim]=th(tim,x,y);
        }
    }
    for(int i=1;i<=qnum;i++)seg_ins(1,tim,1,qry[i].L,qry[i].R,i);
    sort(buy+1,buy+tim+1,cmp);
    sol(1,tim,1,tim,1);
    for(int i=1;i<=qnum;i++)
        printf("%d\n",ans[i]);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章