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

时间: 2024-10-10 18:46:56

BZOJ 3166 HEOI2013 ALO 可持久化trie+st表的相关文章

BZOJ 3166 HEOI2013 Alo 可持久化Trie树

题目大意:给定一个不重复的序列a,在a中任选一个区间,求区间内的次大值与区间内的任意一个其它数的最大的异或值 首先我们枚举次大值 对于一个次大值 它可能选择的另一个数的取值范围为(l,r) 其中l为这个数左侧第二个比它大的数 r为这个数右侧第二个比它大的数 在这个区间内的Trie树中贪心寻找最大值即可 这个区间怎么求呢?我们维护一棵平衡树 将数从大到小将下标加进平衡树 每加进一个下标 比它大的数的下标都在平衡树中 求两次后继就是r 求两次前驱就是l 我偷懒写了set-- #include<set

BZOJ 3166: [Heoi2013]Alo

3166: [Heoi2013]Alo Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 923  Solved: 437[Submit][Status][Discuss] Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

【BZOJ3166】Alo 可持久化trie树

首先我们枚举次大值,然后确定以这个数为次大值的最大区间. 这个区间就是左边第二个比它大的数的下标+1,右边第二个比它大的数的下标-1. 难就难在找到这个区间. 我们考虑将数排序,然后从大到小将数原来的下标插入set,此时set里的值都大于等于当前插入的数. 所以利用set找到前驱的前驱,后继的后继,就是我们需要的区间. 找到区间后,剩下的就是对于一个给定的数,在一段区间里找到一个数使其异或值最大,直接用可持久化trie就可以了. 1 #include <iostream> 2 #include

BZOJ 3230 相似子串 | 后缀数组 二分 ST表

BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过的,也就是考虑左端点在i.右端点在什么范围内时这个子串没有出现过--答案是右端点在[i + height[i] - 1, n]范围内时这个子串没出现过,即右端点在没有被"i与排在前一个的后缀的公共前缀"覆盖的部分时,这个子串没有出现过. 那么我们记录以每个i开头的新子串的数量,求前缀和,然

P4098 [HEOI2013]ALO 可持久化01Trie

$ \color{#0066ff}{ 题目描述 }$ Welcome to ALO ( Arithmetic and Logistic Online).这是一个 VR MMORPG, 如名字所见,到处充满了数学的谜题 现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, -, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,

bzoj3166: [Heoi2013]Alo 可持久化字典树

左右两边的比i大的最近的两个值.然后可持久化字典树即可. #include<bits/stdc++.h> using namespace std; int maxn=0,n,root[1600000],a[50010],cnt=0,l[1600000],r[1600000],p1[50010][25],p2[50010][25],sum[1600000],ans=0,pans=0,l1[50010],r1[50010],l2[50010],r2[50010]; void add(int &am

BZOJ 2119: 股市的预测 [后缀数组 ST表]

2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss] Description 墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势.股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况.经过长时间的观测,墨墨发现很多股票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A

可持久化trie 学习总结

QAQ 以前一直觉得可持久化trie很难,今天强行写了一发觉得还是蛮简单的嘛 自己的模板是自己手写的,写了几道题目并没有出过错误 THUSC的第二题的解法五貌似就是可持久化trie,时间复杂度O(60*n*logn) 不过并没有正解优,听说考场上有人写可持久化树链剖分,也是6得不行QAQ 可持久化trie就是你每次插入一个单词的时候将原来trie的代码每次向下走的时候新建节点 把当前节点信息拷贝给新建节点,通常情况下还要额外对于trie的每个节点维护子树的信息 BZOJ 3261 也算是经典题目