区间相关值问题
2015-10-22 17:18
323 查看
这是一篇奇怪向的总结==
区间max,区间和。。。线段树直接搞
区间中位数,树套树或许可以但或许不优。。。
区间mex(无修改):首先[1,x],1≤x≤n单调扫一遍即可,
同时处理出该位置上的数下一次出现位置,记为next[i]
然后我们对询问排序,考虑i上数对后面数的影响,即为[i,next[i]−1]上mex>=num[i]变为num[i],套上线段树区间修改即可。(ps:带修改或许可以用带修莫队)code:
区间众数(无修改),分块做法,比较简单,参考一下代码吧
g[i][j]表示从第i个块开始到第j个结束的众数
f[x][i]表示x在前i个块内的出现次数
code:
区间max,区间和。。。线段树直接搞
区间中位数,树套树或许可以但或许不优。。。
区间mex(无修改):首先[1,x],1≤x≤n单调扫一遍即可,
同时处理出该位置上的数下一次出现位置,记为next[i]
然后我们对询问排序,考虑i上数对后面数的影响,即为[i,next[i]−1]上mex>=num[i]变为num[i],套上线段树区间修改即可。(ps:带修改或许可以用带修莫队)code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define inf 0x7fffffff #define mid (l+r)/2 #define lch i<<1,l,mid #define rch i<<1|1,mid+1,r using namespace std; int n,m,ans; struct hp{ int mex,delta; }seg[800001]; int ansi[200001]; int next[200001],last[200001]; struct hq{ int l,r,num; bool operator < (const hq &a) const {return (l<a.l)||(l==a.l&&r<a.r);} }qst[200001]; bool mark[200001]; int st[200001],xl[200001]; void build(int i,int l,int r) { seg[i].delta=inf; if (l==r) { seg[i].mex=st[l]; return; } build(lch); build(rch); } void pushdown(int i) { int a=seg[i].delta; seg[i<<1].delta=min(seg[i<<1].delta,a); seg[i<<1|1].delta=min(seg[i<<1|1].delta,a); seg[i<<1].mex=min(seg[i<<1].mex,a); seg[i<<1|1].mex=min(seg[i<<1|1].mex,a); seg[i].delta=inf; } void insert(int i,int l,int r,int x,int y,int a) { if (x<=l&&y>=r) { seg[i].mex=min(seg[i].mex,a); seg[i].delta=min(seg[i].delta,a); return; } if (seg[i].delta!=inf) pushdown(i); if (x<=mid) insert(lch,x,y,a); if (y>mid) insert(rch,x,y,a); } void query(int i,int l,int r,int x) { if (l==x&&l==r) { ans=seg[i].mex; return; } if (seg[i].delta!=inf) pushdown(i); if (x<=mid) query(lch,x); if (x>mid) query(rch,x); } int main() { int i,k=0,now; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) scanf("%d",&xl[i]); for (i=1;i<=n;++i) { mark[xl[i]]=1; if (xl[i]==k) while (mark[k]) k++; st[i]=k; } build(1,1,n); for (i=n;i>=1;--i) { next[i]=last[xl[i]]; if (last[xl[i]]==0) next[i]=n+1; last[xl[i]]=i; } for (i=1;i<=m;++i) { scanf("%d%d",&qst[i].l,&qst[i].r); qst[i].num=i; } sort(qst+1,qst+m+1); now=1; for (i=1;i<=m;++i) { while (now<qst[i].l) { insert(1,1,n,now,next[now]-1,xl[now]); now++; } query(1,1,n,qst[i].r); ansi[qst[i].num]=ans; } for (i=1;i<=m;++i) printf("%d\n",ansi[i]); }
区间众数(无修改),分块做法,比较简单,参考一下代码吧
g[i][j]表示从第i个块开始到第j个结束的众数
f[x][i]表示x在前i个块内的出现次数
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int f[40001][201],g[201][201]; int fa[40001]; int a[40001],b[40001],cnt[40001]; int block[201],num[40001]; int n,m,t,lastans; void work(int l,int r) { int i,st,en,ans,maxn; st=lower_bound(block+1,block+t+1,l)-block; en=lower_bound(block+1,block+t+1,r)-block; if (en-st<=1) { for (i=l;i<=r;++i) num[a[i]]++; ans=0; maxn=0; for (i=l;i<=r;++i) { if ((num[a[i]]>maxn)||(num[a[i]]==maxn&&a[i]<ans)) { maxn=num[a[i]]; ans=a[i]; } num[a[i]]=0; } } else { ans=g[st+1][en-1]; maxn=f[ans][en-1]-f[ans][st]; for (i=l;i<=block[st];++i) num[a[i]]++; for (i=block[en-1]+1;i<=r;++i) num[a[i]]++; for (i=l;i<=block[st];++i) { if ((num[a[i]]+f[a[i]][en-1]-f[a[i]][st]>maxn)||(num[a[i]]+f[a[i]][en-1]-f[a[i]][st]==maxn&&ans>a[i])) { maxn=f[a[i]][en-1]-f[a[i]][st]+num[a[i]]; ans=a[i]; } num[a[i]]=0; } for (i=block[en-1]+1;i<=r;++i) { if ((num[a[i]]+f[a[i]][en-1]-f[a[i]][st]>maxn)||(num[a[i]]+f[a[i]][en-1]-f[a[i]][st]==maxn&&ans>a[i])) { maxn=f[a[i]][en-1]-f[a[i]][st]+num[a[i]]; ans=a[i]; } num[a[i]]=0; } } printf("%d\n",fa[ans]); lastans=fa[ans]; } int main() { int i,per,k,j,size,l,r; int ans,maxn; scanf("%d%d",&n,&m); per=sqrt(n); for (i=1;i<=n;++i) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); size=unique(b+1,b+n+1)-b-1; for (i=1;i<=n;++i) { t=upper_bound(b+1,b+size+1,a[i])-b-1; fa[t]=a[i]; a[i]=t; } t=0; for (i=per;i<=n;i+=per) block[++t]=i; if (block[t]!=n) block[++t]=n; j=1; for (i=1;i<=n;++i) { cnt[a[i]]++; if (i==block[j]) { for (k=1;k<=n;++k) f[k][j]=cnt[k]; j++; } } for (i=1;i<=t;++i) { maxn=0; ans=0; for (j=block[i-1]+1;j<=block[i];++j) if ((f[a[j]][i]-f[a[j]][i-1]>maxn)||(f[a[j]][i]-f[a[j]][i-1]==maxn&&a[j]<ans)) { maxn=f[a[j]][i]-f[a[j]][i-1]; ans=a[j]; } g[i][i]=ans; } for (i=1;i<=t;++i) for (j=i+1;j<=t;++j) { ans=g[i][j-1]; maxn=f[ans][j]-f[ans][i-1]; for (k=block[j-1]+1;k<=block[j];++k) if ((f[a[k]][j]-f[a[k]][i-1]>maxn)||(f[a[k]][j]-f[a[k]][i-1]==maxn&&a[k]<ans)) { maxn=f[a[k]][j]-f[a[k]][i-1]; ans=a[k]; } g[i][j]=ans; } for (i=1;i<=m;++i) { scanf("%d%d",&l,&r); l=(l+lastans-1)%n+1; r=(r+lastans-1)%n+1; if (l>r) swap(l,r); work(l,r); } }
相关文章推荐
- xtrabackup对MySQL进行备份和恢复(centos 6.6)
- 如何查看gnome版本
- vs2008与windbg的使用
- 《大道至简》第四章读后感
- oracle pl/sql之在java中怎么调用oracle函数
- xml的两种解析方式sax和dom解析的区别
- Spring Aop实例
- Hibernate 、多表关联映射-多对一关系(many-to-one)
- eclipse 统计代码总行数
- 九度OJ 1080:进制转换 (进制转换)
- 毕业五年后拉开大家差距的原因
- IOS开发:iOS的xmppframework简介
- 学习笔记 一步步了解webpack
- IIS与ASP.NET中的队列
- Hibernate 、多表关联映射-多对一关系(many-to-one)
- 九度OJ 1080:进制转换 (进制转换)
- poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&&缩点】
- String 总结
- 一个球从100 米高的自由落下的反弹高度
- Android 使用Fragment实现兼容手机和平板的程序