【BZOJ4137】【FJOI2015】火星商店问题
线段树套可持久化Trie即可。
如果把一个商品的时间看成横坐标,商店编号看成纵坐标,那么原题可以转化成给定一个坐标平面上的个点,每个点有点权,次查询,每次给定,查询一个矩形区域内的最大值。
一个直观的想法是树套树,对轴建线段树,内层使用可持久化Trie支持查询区间的最大值。注意到可持久化Trie要求按顺序插入,那么我们将所有点按纵坐标排序后再插入线段树。询问时找到这个询问对应的所有横坐标区间,分别查询之后取max即可。
看起来这题已经解决了,然而这个做法的空间复杂度是的,无法通过的空间限制。
那怎么办办呢?注意到我们可以离线,我们预先把所有点和询问挂在它们对应的线段树节点上,这样我们只需要对于每个线段树节点建立一次可持久化Trie就可以了。
这样就解决了这题,时间复杂度,空间复杂度。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MAXSIZE=10000020;int bufpos;char buf[MAXSIZE];#define NEG 0void init(){#ifdef LOCALfreopen("4137.txt","r",stdin);#endifbuf[fread(buf,1,MAXSIZE,stdin)]='\0';bufpos=0;}#if NEGint readint(){bool isneg;int val=0;for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);bufpos+=(isneg=buf[bufpos]=='-');for(;isdigit(buf[bufpos]);bufpos++)val=val*10+buf[bufpos]-'0';return isneg?-val:val;}#elseint readint(){int val=0;for(;!isdigit(buf[bufpos]);bufpos++);for(;isdigit(buf[bufpos]);bufpos++)val=val*10+buf[bufpos]-'0';return val;}#endifchar readchar(){for(;isspace(buf[bufpos]);bufpos++);return buf[bufpos++];}int readstr(char* s){int cur=0;for(;isspace(buf[bufpos]);bufpos++);for(;!isspace(buf[bufpos]);bufpos++)s[cur++]=buf[bufpos];s[cur]='\0';return cur;}const int maxn=100005;struct trie{struct node{int sum,ls,rs;}t[maxn*21];int cur;void clear(){cur=ver=0;}int rt[maxn],ver;void insert(int x){t[++cur]=t[rt[ver]];int o=rt[++ver]=cur;for(int i=17;i>=0;i--){t[o].sum++;int &v=(x>>i&1)?t[o].rs:t[o].ls;t[++cur]=t[v];o=v=cur;}t[o].sum++;}int query(int l,int r,int x){// printf("query %d %d %d\n",l,r,x);int lo=rt[l-1],ro=rt[r],ans=0;for(int i=17;i>=0;i--){if (x>>i&1){if (t[t[ro].ls].sum>t[t[lo].ls].sum)lo=t[lo].ls,ro=t[ro].ls,ans|=1<<i;else lo=t[lo].rs,ro=t[ro].rs;}else{if (t[t[ro].rs].sum>t[t[lo].rs].sum)lo=t[lo].rs,ro=t[ro].rs,ans|=1<<i;else lo=t[lo].ls,ro=t[ro].ls;}}// puts("after query");return ans;}}t;struct query{int l,r,x,ans;}w[maxn];struct item{int p,v;bool operator <(const item& rhs)const{return p<rhs.p;}};int ans[maxn];struct segtree{int n;vector<int> q[maxn*4];vector<item> a[maxn*4];int p;item it;void update(int o,int l,int r){// printf("update %d %d %d\n",o,l,r);a[o].push_back(it);if (l==r)return;int mid=(l+r)/2;if (p<=mid)update(o*2,l,mid);else update(o*2+1,mid+1,r);}int ql,qr,id;void addq(int o,int l,int r){if (ql<=l && qr>=r){q[o].push_back(id);return;}int mid=(l+r)/2;if (ql<=mid)addq(o*2,l,mid);if (qr>mid)addq(o*2+1,mid+1,r);}void work(int o){t.clear();sort(a[o].begin(),a[o].end());for(int i=0;i<a[o].size();i++)t.insert(a[o][i].v);for(int i=0;i<q[o].size();i++){query & qwq=w[q[o][i]];int l=lower_bound(a[o].begin(),a[o].end(),(item){qwq.l,0})-a[o].begin()+1,r=upper_bound(a[o].begin(),a[o].end(),(item){qwq.r,0})-a[o].begin();if (l>r)continue;qwq.ans=max(qwq.ans,t.query(l,r,qwq.x));}}void work(){for(int i=1;i<=4*n;i++)if (q[i].size() && a[i].size())work(i);}}s;int main(){init();int n=readint(),m=readint();s.n=m+1;for(int i=1;i<=n;i++)t.insert(readint());// puts("WTF");int day=1,cur=0;for(int o=1;o<=m;o++){int op=readint();if (!op){int p=readint(),v=readint();s.p=++day,s.it=(item){p,v};s.update(1,1,s.n);}else{int l=readint(),r=readint(),x=readint(),d=readint();// printf("query %d %d %d %d\n",l,r,x,d);w[++cur]=(query){l,r,x,t.query(l,r,x)};if (!d)continue;s.ql=max(day-d+1,1),s.qr=day,s.id=cur;s.addq(1,1,s.n);}}// puts("WTF");s.work();// printf("cur=%d\n",cur);for(int i=1;i<=cur;i++)printf("%d\n",w[i].ans);}
Written with StackEdit.
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
本文链接:https://www.q234rty.top/2018/03/04/bzoj4137/
