博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】[SDOI2009]HH的项链
阅读量:6202 次
发布时间:2019-06-21

本文共 2748 字,大约阅读时间需要 9 分钟。

【算法】主席树||离线+树状数组

【题解】

主席树经典应用:找区间不同的数字个数。

做法:记录每个数上一次出现的位置last[i],对last建权值线段树,对于区间询问last[i]<L的数字个数。

注意权值范围是last[i],也即0~n。

注意x=0时返回,否则可能c<0就完了。

#include
#include
#include
#include
using namespace std;const int maxn=50010;struct tree{
int l,r,sum;}t[1000010];int a[maxn],n,sz,last[maxn],root[maxn],b[1000010],m;int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t;}void insert(int l,int r,int &x,int y,int c){ x=++sz; t[x]=t[y];t[x].sum++; if(l==r)return; int mid=(l+r)>>1; if(c<=mid)insert(l,mid,t[x].l,t[y].l,c); else insert(mid+1,r,t[x].r,t[y].r,c);}int ask(int l,int r,int x,int c){ if(x==0)return 0; if(r<=c)return t[x].sum; int mid=(l+r)>>1,ans=0; if(c>mid)ans+=ask(mid+1,r,t[x].r,c); ans+=ask(l,mid,t[x].l,c); return ans;} int main(){ n=read(); for(int i=1;i<=n;i++){ a[i]=read(); last[i]=b[a[i]]; b[a[i]]=i; } for(int i=1;i<=n;i++)insert(0,n,root[i],root[i-1],last[i]); m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); printf("%d\n",ask(0,n,root[v],u-1)-ask(0,n,root[u-1],u-1)); } return 0;}
View Code

 

另一种做法,考虑对询问离线并按左端点排序,那么一个位置对答案有贡献仅当左端点已经过和它相同数字的上一位置,那么就是求区间和(有贡献的点+1),显然是树状数组。

具体过程:初始同一个数字最前面的位置+1,然后1~n每次nex[i]位置+1,同时回答询问ans=ask(r)-ask(l-1),因为左端点经过了所以区间同一个数最多只存在一个。

#include
#include
#include
#include
#define lowbit(x) x&(-x)using namespace std;const int maxn=200010,maxL=1000010;int a[maxn],c[maxn],n,m,ans[maxn],anss[maxn],nex[maxn],b[maxL]; int read(){ char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c=='-')t=-1; do{s=s*10+c-'0';}while(isdigit(c=getchar())); return s*t;}struct cyc{
int l,r,id;}d[maxn];bool cmp(cyc a,cyc b){
return a.l
=1;i-=lowbit(i))nowans+=c[i];return nowans;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ a[i]=read(); } for(int i=0;i<=maxL;i++)b[i]=n+1; for(int i=n;i>=1;i--){ nex[i]=b[a[i]]; b[a[i]]=i; } for(int i=0;i<=maxL;i++)if(b[i])insert(b[i]); scanf("%d",&m); for(int i=1;i<=m;i++){ d[i].l=read();d[i].r=read(); d[i].id=i; } sort(d+1,d+m+1,cmp); int now=1; for(int i=1;i<=n&&now<=m;i++){ while(now<=m&&d[now].l==i){ans[now]=ask(d[now].r)-ask(d[now].l-1);now++;} insert(nex[i]); } for(int i=1;i<=m;i++)anss[d[i].id]=ans[i]; for(int i=1;i<=m;i++)printf("%d\n",anss[i]); return 0;}
View Code

常数约为主席树的1/2。

转载于:https://www.cnblogs.com/onioncyc/p/7471245.html

你可能感兴趣的文章
基于matlab的fft变换中参数的设置
查看>>
如何查找JSP页面中的错误
查看>>
2016 年总结
查看>>
Python学习开始
查看>>
Android应用程序消息处理机制(Looper、Handler)分析(4)
查看>>
C++ 类成员的构造和析构顺序
查看>>
将String转化成Stream,将Stream转换成String
查看>>
java路径Java开发中获得非Web项目的当前项目路径
查看>>
Google API设计指南-资源名称
查看>>
最全React技术栈技术资料汇总(收藏)
查看>>
【工具使用系列】关于 MATLAB 遗传算法与直接搜索工具箱,你需要知道的事
查看>>
flex 学习笔记 stage
查看>>
Kali-linux Arpspoof工具
查看>>
java中三个类别加载器的关系以及各自加载的类的范围
查看>>
PDF文档页面如何重新排版?
查看>>
基于http协议使用protobuf进行前后端交互
查看>>
python3 + Django + uwsgi + nginx 配置部署笔记
查看>>
UML设计一个电影票务销售系统(四)
查看>>
如何给VEEAM 7 分配角色权限
查看>>
AlphaGo Zero用它来调参?【高斯过程】到底有何过人之处?
查看>>