BZOJ 3166 HEOI2013 ALO 可持久化trie+st表

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3166(洛谷上也有)

 

题意概述:

  给出一个序列,对于一个区间,其权值为区间中的次大值亦或区间中任意一个数的结果的最大值。求区间权值的最大值。

 

分析:

  考虑每个点作为区间次大的状态,发现对于每个点至多有两个最长区间其为次大值(为了让异或结果最大当然是区间越长越好,选择最多),用二分+静态RMQ算出这两个区间再在可持久化trie上面贪心即可。

  论如何现场yy可持久化数据结构23333(基于可持久化线段树的yy算法)

  注意一下算区间的边界问题。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 using namespace std;
 13 const int MAXN=50005;
 14 
 15 int N,a[MAXN];
 16 struct data{ int l,r,v; }q[MAXN<<1]; int cnt;
 17 int mx[MAXN][18];
 18 struct Trie{
 19     static const int maxn=1600000;
 20     static const int maxm=50005;
 21     int np,root[maxm],to[maxn][2],sum[maxn];
 22     Trie(){ np=sum[0]=0; memset(to[0],0,sizeof(to[0])); }
 23     int copynode(int p){
 24         memcpy(to[++np],to[p],sizeof(to[p]));
 25         sum[np]=sum[p];
 26         return np;
 27     }
 28     void ins(int ver,int x){
 29         root[ver]=copynode(root[ver-1]);
 30         int p=root[ver],d;
 31         for(int i=30;i>=0;i--){
 32             sum[p]++,d=(x>>i)&1;
 33             if(!to[p][d]){
 34                 to[p][d]=++np,sum[np]=0;
 35                 memset(to[np],0,sizeof(to[np]));
 36                 p=to[p][d];
 37             }
 38             else to[p][d]=copynode(to[p][d]),p=to[p][d];
 39         }
 40         sum[p]++;
 41     }
 42     int query(int A,int B,int w){
 43         int p1=root[A],p2=root[B],d;
 44         for(int i=30;i>=0;i--){
 45             d=((w>>i)&1)^1;
 46             if(sum[to[p2][d]]-sum[to[p1][d]])
 47                 p1=to[p1][d],p2=to[p2][d],w^=d<<i;
 48             else p1=to[p1][d^1],p2=to[p2][d^1],w^=1-d<<i;
 49         }
 50         return w;
 51     }
 52 }trie;
 53 
 54 void _scanf(int &x)
 55 {
 56     x=0;
 57     char c=getchar();
 58     while(c<'0'||c>'9') c=getchar();
 59     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 60 }
 61 void data_in()
 62 {
 63     _scanf(N);
 64     for(int i=1;i<=N;i++) _scanf(a[i]);
 65 }
 66 void get_st()
 67 {
 68     for(int i=1;i<=N;i++) mx[i][0]=a[i];
 69     for(int i=N;i>=1;i--)
 70     for(int j=1;(1<<j)<=N-i+1;j++)
 71         mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
 72 }
 73 int query(int x,int y)
 74 {
 75     int k=0;
 76     while((1<<k+1)<y-x+1) k++;
 77     return max(mx[x][k],mx[y-(1<<k)+1][k]);
 78 }
 79 int getp1(int p,int v)
 80 {
 81     int re=p,mid,L=1,R=p;
 82     while(L<R){
 83         mid=L+R>>1;
 84         if(query(mid,p-1)>v) L=mid+1;
 85         else R=mid,re=mid;
 86     }
 87     return re;
 88 }
 89 int getp2(int p,int v)
 90 {
 91     int re=p,mid,L=p+1,R=N+1;
 92     while(L<R){
 93         mid=L+R>>1;
 94         if(query(p+1,mid)>v) R=mid;
 95         else L=mid+1,re=mid;
 96     }
 97     return re;
 98 }
 99 void work()
100 {
101     get_st();
102     for(int i=1;i<=N;i++){
103         int p1=getp1(i,a[i]),p2=getp2(i,a[i]);
104         if(p1>1) q[++cnt]=(data){getp1(p1-1,a[i]),p2,a[i]};
105         if(p2<N) q[++cnt]=(data){p1,getp2(p2+1,a[i]),a[i]};
106     }
107     for(int i=1;i<=N;i++) trie.ins(i,a[i]);
108     int ans=0;
109     for(int i=1;i<=cnt;i++)
110         ans=max(ans,trie.query(q[i].l-1,q[i].r,q[i].v));
111     printf("%d\n",ans);
112 }
113 int main()
114 {
115     data_in();
116     work(); 
117     return 0;
118 }

 

转载于:https://www.cnblogs.com/KKKorange/p/8728091.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值