[BZOJ3166][Heoi2013]Alo(可持久化线段树+可持久化tire树)
2016-12-15 16:41
477 查看
题目描述
传送门题解
xor的操作很容易想到可持久化trie树,但是关键是次大值比较头疼。可以发现,如果可以维护出来每一个点向前和向后第一个以及第二个比它大的值的位置就可以确定区间了。
实际上,可以用可持久化线段树的思想来搞。将所有的值从大到小排序,然后按照每一个点的位置插入线段树,相当于对于每一个点,比它大的点已经都插入进去了。每一次查询就是从权值大于当前点的线段树里找出当前点前驱的前驱,一个后继,或者是找出后继的后继,一个前驱,来确定一个区间,这样就可以用可持久化trie树来搞了。
这道题维护的两个量都牵扯到了可持久化,让我对可持久化有了更全面的认识。
我比较傻逼,据说我用了可持久化线段树的那个东西用个数组随便维护一下就行了T_T
UPD:怎么感觉线段树根本不用可持久化啊…蠢死了
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> using namespace std; #define inf 1000000000 #define N 50005 #define lg 30 struct hp{int val,id,rk;}a ; int n,ans,Max; namespace pt { int sz; int root ,maxn[N*35],minn[N*35],ls[N*35],rs[N*35]; void clear() { memset(minn,127,sizeof(minn)); } void update(int now) { maxn[now]=max(maxn[ls[now]],maxn[rs[now]]); minn[now]=min(minn[ls[now]],minn[rs[now]]); } void change(int &now,int l,int r,int x) { int mid=(l+r)>>1; ls[++sz]=ls[now],rs[sz]=rs[now];now=sz; if (l==r) { maxn[now]=minn[now]=x; return; } if (x<=mid) change(ls[now],l,mid,x); else change(rs[now],mid+1,r,x); update(now); } int query_max(int now,int l,int r,int lrange,int rrange) { if (lrange>rrange) return 0; int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return maxn[now]; if (lrange<=mid) ans=max(ans,query_max(ls[now],l,mid,lrange,rrange)); if (mid+1<=rrange) ans=max(ans,query_max(rs[now],mid+1,r,lrange,rrange)); return ans; } int query_min(int now,int l,int r,int lrange,int rrange) { if (lrange>rrange) return n+1; int mid=(l+r)>>1,ans=inf+1; if (lrange<=l&&r<=rrange) return minn[now]; if (lrange<=mid) ans=min(ans,query_min(ls[now],l,mid,lrange,rrange)); if (mid+1<=rrange) ans=min(ans,query_min(rs[now],mid+1,r,lrange,rrange)); return ans; } } namespace trie { int sz; int root ,sum[N*35],ch[N*35][2]; void change(int &now,int x,int dep) { sum[++sz]=sum[now]+1,ch[sz][0]=ch[now][0],ch[sz][1]=ch[now][1];now=sz; if (dep==-1) return; int k=(x>>dep)&1; change(ch[now][k],x,dep-1); } void query(int l,int r,int x,int dep) { if (dep==-1) return; int k=(x>>dep)&1; if (sum[ch[r][k^1]]-sum[ch[l][k^1]]>0) { ans|=1<<dep; query(ch[l][k^1],ch[r][k^1],x,dep-1); } else query(ch[l][k],ch[r][k],x,dep-1); } } int cmpval(hp a,hp b) { return a.val>b.val; } int cmpid(hp a,hp b) { return a.id<b.id; } int main() { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&a[i].val),a[i].id=i; sort(a+1,a+n+1,cmpval); pt::clear(); for (int i=1;i<=n;++i) { a[i].rk=i; pt::root[i]=pt::root[i-1]; pt::change(pt::root[i],1,n,a[i].id); } sort(a+1,a+n+1,cmpid); for (int i=1;i<=n;++i) { trie::root[i]=trie::root[i-1]; trie::change(trie::root[i],a[i].val,lg); } for (int i=1;i<=n;++i) { bool flag;int loc1,loc2; flag=false; loc1=pt::query_max(pt::root[a[i].rk-1],1,n,1,i-1); if (loc1!=0) flag=true; loc1=pt::query_max(pt::root[a[i].rk-1],1,n,1,loc1-1); loc2=pt::query_min(pt::root[a[i].rk-1],1,n,i+1,n); if (loc2>n) loc2=n+1; ans=0; if (loc1<loc2-1&&flag) trie::query(trie::root[loc1],trie::root[loc2-1],a[i].val,lg); Max=max(Max,ans); flag=false; loc1=pt::query_min(pt::root[a[i].rk-1],1,n,i+1,n); if (loc1<=n) flag=true; loc1=pt::query_min(pt::root[a[i].rk-1],1,n,loc1+1,n); if (loc1>n) loc1=n+1; loc2=pt::query_max(pt::root[a[i].rk-1],1,n,1,i-1); ans=0; if (loc2<loc1-1&&flag) trie::query(trie::root[loc2],trie::root[loc1-1],a[i].val,lg); Max=max(Max,ans); } printf("%d\n",Max); }
总结
①维护当前点向前第二个大于/小于它的值可以尝试用可持久化数据结构。相关文章推荐
- 单例模式
- 博为峰Java技术题 ——JavaSE Java Swing顶层容器类和包含层次Ⅱ
- Android ProGuard 混淆 详解
- 项目技术框架
- 从手工测试逆袭为NB自动化测试的学习路线
- 移动端特效下载网站分享
- mongodb 地理位置搜寻
- <context:component-scan>使用说明
- Python用UUID库生成唯一ID的方法示例
- 浅谈JavaScript的自动垃圾收集机制
- python学习笔记6.1-类的认识
- 样式优先级
- find命令
- Oracle 触发器的简单命令
- (转)小议创业初期的技术选择
- STM32 相关文章
- 利用Mongodb做地理空间查询
- java 计算今天还剩多少时间
- 基于scala 新版API操作HBase
- Kafka学习整理三(borker(0.9.0及0.10.0)配置)