1. 程式人生 > >[FJOI2015]火星商店問題(分治+可持久化)

[FJOI2015]火星商店問題(分治+可持久化)

stream query 獨立 活動 修改 git getch algorithm 給定

題目描述

火星上的一條商業街裏按照商店的編號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。

題解

考慮如果沒有時間限制,我們可以選取的區間為連續一段,那樣就是簡單的按位貪心,可以用可持久化trie維護。

現在有了時間限制,我們考慮分治,每個詢問所覆蓋的都是連續一段區間,而且修改之間是獨立的,我們可以把每個詢問拆成log個掛在按照時間建立的線段樹上,然後按時間在線段樹上分治。

我們可以每次都重構trie,復雜度是對的。

代碼

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 210002
using namespace std;
vector<int>vec[N<<2];
int len=18,tot,inv[20],T[N],ans[N],n,m,tim,top;
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while
(!isdigit(c)){if(c==-)f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct TRIE{ int ch[N*22][2],size[N*22]; inline void ins(int &now,int pre,int x,int deep){ now=++tot;ch[now][0]=ch[pre][0];ch[now][1]=ch[pre][1];size[now]=size[pre]+1; if(deep<0)return; if(x&(1<<deep))ins(ch[now][1],ch[pre][1],x,deep-1); else ins(ch[now][0],ch[pre][0],x,deep-1); } inline int query(int now,int pre,int x,int deep){ if(deep<0)return 0; int o=(x&(1<<deep))!=0,num=size[ch[now][!o]]-size[ch[pre][!o]]; if(num)return inv[deep]+query(ch[now][!o],ch[pre][!o],x,deep-1); else return query(ch[now][o],ch[pre][o],x,deep-1); } }tr; struct node{ int pos,val,tim; bool operator <(const node &b)const{return pos<b.pos;} }co[N],q1[N],q2[N]; struct nod{int l,r,x,st,en;}q[N]; void calc(int cnt,int l,int r){ int top=0;tot=0; for(int i=l;i<=r;++i){ ++top; tr.ins(T[top],T[top-1],co[i].val,len); } for(int i=0;i<vec[cnt].size();++i){ int id=vec[cnt][i];node x; x.pos=q[id].l-1; int L=upper_bound(co+l,co+r+1,x)-co-l;//!!!! x.pos=q[id].r; int R=upper_bound(co+l,co+r+1,x)-co-l; ans[id]=max(ans[id],tr.query(T[R],T[L],q[id].x,len)); } } void upd(int cnt,int l,int r,int L,int R,int x){ if(L>R)return; if(l>=L&&r<=R){vec[cnt].push_back(x);return;} int mid=(l+r)>>1; if(mid>=L)upd(cnt<<1,l,mid,L,R,x); if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,x); } void solve(int cnt,int l,int r,int L,int R){ if(l>r||L>R)return; int mid=(l+r)>>1; calc(cnt,L,R); int o=0,p=0; for(int i=L;i<=R;++i){ if(co[i].tim<=mid)q1[++o]=co[i]; else q2[++p]=co[i]; } for(int i=1;i<=o;++i)co[L+i-1]=q1[i]; for(int i=1;i<=p;++i)co[L+o+i-1]=q2[i]; if(l!=r)solve(cnt<<1,l,mid,L,L+o-1); solve(cnt<<1|1,mid+1,r,L+o,R); } int main(){ n=rd();m=rd();int l,r,x,d,v,opt; for(int i=1;i<=n;++i)x=rd(),tr.ins(T[i],T[i-1],x,len); inv[0]=1; for(int i=1;i<=len;++i)inv[i]=inv[i-1]<<1; for(int i=1;i<=m;++i){ opt=rd(); if(opt){ l=rd();r=rd();x=rd();d=rd(); q[++top]=nod{l,r,x,max(1,tim-d+1),tim}; ans[top]=tr.query(T[r],T[l-1],x,len); } else{ tim++;x=rd();v=rd();co[tim]=node{x,v,tim}; } } sort(co+1,co+tim+1); for(int i=1;i<=top;++i)upd(1,1,tim,q[i].st,q[i].en,i); solve(1,1,tim,1,tim); for(int i=1;i<=top;++i)printf("%d\n",ans[i]); return 0; }

[FJOI2015]火星商店問題(分治+可持久化)