【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)

【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)

语文没学好不要写省选题面!!!!

题目大意:

\(n\)个集合,每个集合有个任意时刻都可用的初始元素。现在有\(m\)个操作

  • 询问\([l,r]\)的集合中,使得\(v\oplus x\)最大的那个元素,输出\(v\oplus x\)。同时要求这个\(x\)是最近\(d\)次插入中插入的。
  • 在集合\(i\)中插入一个数\(x\)

考虑这样一个做法,直接开一颗线段树,线段树每个节点是一个\(trie\)树(不用可持久化),维护节点代表的区间中的集合的所有元素构成的\(trie\)树。

考虑时间复杂度

  • 每次询问被拆成\(\log n\)个询问,加上\(trie\)的复杂度\(O(n \log^2n)\)
  • 每次插入也被拆成\(\log n\)个插入,加上\(trie\)的复杂度\(O(n \log^2n)\)

考虑空间复杂度

  • 考虑每个元素被插入了\(O(\log n)\)次,加上\(trie\)树就是\(O(n\log^2 n)\)

trie节点要开3e7个,就问你够不够暴力。

7.59s / 288.88MB / 1.92KB C++11

//@winlere
#include<iostream>
#include<cstdio>
#include<algorithm>
#define mid ((l+r)>>1)
#define lef L,R,l,mid,pos<<1
#define rgt L,R,mid+1,r,pos<<1|1

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}

const int maxn=1e5+5;
const int inf=1e9+7;

struct E{
      int son[2],cnt;
      E(){son[0]=son[1]=0;cnt=-inf;}
      inline int& operator[](int x){return son[x];}
}dic[25000000];
int seg[maxn<<2],cnt,n,m;

inline void insert(const int&now,const int&x,const int&d){
      int k=now;
      dic[k].cnt=max(dic[k].cnt,d);
      for(int t=30;~t;--t){
        int f=x>>t&1;
        k=dic[k][f]?dic[k][f]:dic[k][f]=++cnt,dic[k].cnt=max(dic[k].cnt,d);
      }
}

int getans(const int&now,const int&x,const int&d){
      int k=now,ret=0;
      for(int t=30;~t;--t){
        int f=x>>t&1;
        if(dic[k][f^1]&&dic[dic[k][f^1]].cnt>=d) k=dic[k][f^1],ret|=1<<t;
        else k=dic[k][f];
      }
      return ret;
}

void upd(const int&x,const int&d,const int&L,const int&R,const int&l,const int&r,const int&pos){
      if(L>r||R<l)return;
      if(!seg[pos]) seg[pos]=++cnt;
      insert(seg[pos],x,d);
      if(l==r) return;
      upd(x,d,lef); upd(x,d,rgt);
}

int que(const int&ans,const int&d,const int&L,const int&R,const int&l,const int&r,const int&pos){
      if(L>r||R<l) return 0;
      if(L<=l&&r<=R) return getans(seg[pos],ans,d);
      return max(que(ans,d,lef),que(ans,d,rgt));
}

int main(){
      n=qr(); m=qr();
      int day=1;
      for(int t=1;t<=n;++t)
        upd(qr(),inf,t,t,1,n,1);
      for(int t=1,t1,t2,t3,t4;t<=m;++t)
        if(qr()) t1=qr(),t2=qr(),t3=qr(),t4=qr(),printf("%d\n",que(t3,max(0,day-t4+1),t1,t2,1,n,1));
            else ++day,t1=qr(),t2=qr(),upd(t2,day,t1,t1,1,n,1);
      return 0;
}


posted @ 2019-09-17 22:24 谁是鸽王 阅读(...) 评论(...) 编辑 收藏