主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)
1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665
(POJ2104)http://poj.org/problem?id=2104
(POJ2761)http://poj.org/problem?id=2761
题意:求区间第K大,主席树模板题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=;
int tot,n,q,nowm;
int a[maxn],t[maxn];
int c[maxn<<],lson[maxn<<],rson[maxn<<];
int T[maxn]; void init_hash()
{
for ( int i=;i<=n;i++ ) t[i]=a[i];
sort(t+,t++n);
nowm=unique(t+,t++n)-(t+);
} int hash_(int x)
{
return lower_bound(t+,t++nowm,x)-t;
} void build(int &root,int l,int r)
{
root=++tot;
if ( l==r ) return;
int mid=(l+r)/;
build(lson[root],l,mid);
build(rson[root],mid+,r);
} void update(int root,int &rt,int p,int val,int l,int r)
{
rt=++tot;
lson[rt]=lson[root],rson[rt]=rson[root];
c[rt]=c[root]+val;
if ( l==r ) return;
int mid=(l+r)/;
if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
else update(rson[rt],rson[rt],p,val,mid+,r);
} int query(int rt_,int rt,int l,int r,int k)
{
if ( l==r ) return l;
int mid=(l+r)/;
int sum=c[lson[rt_]]-c[lson[rt]];
if ( sum>=k ) return query(lson[rt_],lson[rt],l,mid,k);
else return query(rson[rt_],rson[rt],mid+,r,k-sum);
} int main()
{
int Case;
scanf("%d",&Case);
while(Case++){
scanf("%d%d",&n,&q);
tot=;
for ( int i=;i<=n;i++ ) scanf("%d",&a[i]);
init_hash();
build(T[],,nowm);
for ( int i=;i<=n;i++ )
{
int pos=hash_(a[i]);
update(T[i-],T[i],pos,,,nowm);
}
while ( q-- )
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(T[r],T[l-],,nowm,k)]);
}
}
return ;
}
2.(HDOJ4417)http://acm.hdu.edu.cn/showproblem.php?pid=4417
题意:求给定区间<=k的数有多少
分析:在模板上将query部分修改一下即可,对于区间[L,R]来说,只需要将第R颗线段树上的[0,k]区间内的值减去第L-1颗线段树上对应区间即可。离线在线都行,离线做法需要将每次访问的k也添加进入hash数组,而对于在线来说转化后的数转化前相对于给定的k来说只能变小不能变大即可
注意:题目给的区间范围从0开始,要将其转化成从1开始
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+;
const int maxm=3e6+;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[maxn],lson[maxm],rson[maxm],c[maxm]; void init_hash()
{
for ( int i=;i<=n;i++ ) t[i]=a[i];
sort(t+,t++n);
m=unique(t+,t++n)-(t+);
} int build(int l,int r)
{
int root=tot++;
c[root]=;
if ( l!=r )
{
int mid=(l+r)/;
lson[root]=build(l,mid);
rson[root]=build(mid+,r);
}
return root;
} int hash_(int x)
{
return lower_bound(t+,t++m,x)-t;
} int update(int root,int pos,int val)
{
int rt=tot++,tmp=rt;
c[rt]=c[root]+val;
int l=,r=m;
while ( l<r )
{
int mid=(l+r)/;
if ( pos<=mid )
{
lson[rt]=tot++;rson[rt]=rson[root];
rt=lson[rt];root=lson[root];
r=mid;
}
else
{
rson[rt]=tot++;lson[rt]=lson[root];
rt=rson[rt];root=rson[root];
l=mid+;
}
c[rt]=c[root]+val;
}
return tmp;
} int query(int lrt,int rrt,int k)
{
int ret=;
int l=,r=m;
while ( l<r )
{
int mid=(l+r)/;
if ( k<=mid )
{
r=mid;
lrt=lson[lrt];
rrt=lson[rrt];
}
else
{
ret+=c[lson[rrt]]-c[lson[lrt]];
l=mid+;
lrt=rson[lrt];
rrt=rson[rrt];
}
}
ret+=c[rrt]-c[lrt];
return ret;
} int main()
{
int Case,h;
scanf("%d",&Case);
for ( h=;h<=Case;h++ )
{
scanf("%d%d",&n,&q);
tot=;
for ( int i=;i<=n;i++ )
{
scanf("%d",&a[i]);
a[i]++;
}
init_hash();
T[]=build(,m);
for ( int i=;i<=n;i++ )
{
int pos=hash_(a[i]);
T[i]=update(T[i-],pos,);
}
printf("Case %d:\n",h);
while ( q-- )
{
int l,r,k,p;
scanf("%d%d%d",&l,&r,&k);
l++,r++,k++;
p=hash_(k);
if ( t[p]>k ) p--;
if ( p== ) printf("0\n");
else printf("%d\n",query(T[l-],T[r],p));
}
}
return ;
} HDOJ4417(在线)
在线
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+;
const int maxm=3e6+;
int n,q,m,tot;
int a[maxn],t[maxn*],l[maxn],r[maxn],val[maxn];
int T[maxn],lson[maxm],rson[maxm],c[maxm]; void init_hash()
{
for ( int i=;i<=n;i++ ) t[i]=a[i];
for ( int i=;i<=q;i++ ) t[i+n]=val[i];
sort(t+,t++n+q);
m=unique(t+,t++n+q)-(t+);
} int build(int l,int r)
{
int root=tot++;
c[root]=;
if ( l!=r )
{
int mid=(l+r)/;
lson[root]=build(l,mid);
rson[root]=build(mid+,r);
}
return root;
} int hash_(int x)
{
return lower_bound(t+,t++m,x)-t;
} int update(int root,int pos,int val)
{
int rt=tot++,tmp=rt;
c[rt]=c[root]+val;
int l=,r=m;
while ( l<r )
{
int mid=(l+r)/;
if ( pos<=mid )
{
lson[rt]=tot++;rson[rt]=rson[root];
rt=lson[rt];root=lson[root];
r=mid;
}
else
{
rson[rt]=tot++;lson[rt]=lson[root];
rt=rson[rt];root=rson[root];
l=mid+;
}
c[rt]=c[root]+val;
}
return tmp;
} int query(int lrt,int rrt,int k)
{
int ret=;
int l=,r=m;
while ( l<r )
{
int mid=(l+r)/;
if ( k<=mid )
{
r=mid;
lrt=lson[lrt];
rrt=lson[rrt];
}
else
{
ret+=c[lson[rrt]]-c[lson[lrt]];
l=mid+;
lrt=rson[lrt];
rrt=rson[rrt];
}
}
ret+=c[rrt]-c[lrt];
return ret;
} int main()
{
int Case,h;
scanf("%d",&Case);
for ( h=;h<=Case;h++ )
{
scanf("%d%d",&n,&q);
tot=;
for ( int i=;i<=n;i++ )
{
scanf("%d",&a[i]);
a[i]++;
}
for ( int i=;i<=q;i++ ) {
scanf("%d%d%d",&l[i],&r[i],&val[i]);
l[i]++,r[i]++,val[i]++;
}
init_hash();
T[]=build(,m);
for ( int i=;i<=n;i++ )
{
int pos=hash_(a[i]);
T[i]=update(T[i-],pos,);
}
printf("Case %d:\n",h);
for ( int i=;i<=q;i++ )
{
int L,R,k;
L=l[i],R=r[i],k=val[i];
k=hash_(k);
printf("%d\n",query(T[L-],T[R],k));
}
}
return ;
} HDOJ4417(离线)
离线
3.(SPOJ3267)http://www.spoj.com/problems/DQUERY/
题意:给出一个长度为n 的数列,有q 个询问,每个询问给出数对 [i,j],需要你给出这一段中有多少不同的数字
分析:利用map记录每个数的位置,主席树建新树的时候,如果当前元素出现过,那么把这个元素上次出现的位置减一,然后当前位置加一,如果没出现过就是普通的建树操作。
对于查询[l, r]我们只需要取出第r棵树,然后输出这棵树[l,r]之间的和,因为是按从1到n的顺序插入的,所以每次只需要求>=l的个数即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int maxn=3e4+;
const int maxm=3e6+;
int n,q,tot;
int a[maxn];
int T[maxn],lson[maxm],rson[maxm],c[maxm]; int build(int l,int r)
{
int root=tot++;
c[root]=;
if ( l!=r )
{
int mid=(l+r)/;
lson[root]=build(l,mid);
rson[root]=build(mid+,r);
}
return root;
} int update(int root,int pos,int val)
{
int rt=tot++,tmp=rt;
c[rt]=c[root]+val;
int l=,r=n;
while ( l<r )
{
int mid=(l+r)/;
if ( pos<=mid )
{
lson[rt]=tot++;rson[rt]=rson[root];
rt=lson[rt];root=lson[root];
r=mid;
}
else
{
rson[rt]=tot++;lson[rt]=lson[root];
rt=rson[rt];root=rson[root];
l=mid+;
}
c[rt]=c[root]+val;
}
return tmp;
} int query(int rt,int lpos)
{
int ret=;
int l=,r=n;
while ( lpos>l )
{
int mid=(l+r)/;
if ( lpos<=mid )
{
r=mid;
ret+=c[rson[rt]];
rt=lson[rt];
}
else
{
rt=rson[rt];
l=mid+;
}
}
return ret+c[rt];
} int main()
{
int Case;
while ( scanf("%d",&n)!=EOF )
{
tot=;
for ( int i=;i<=n;i++ ) scanf("%d",&a[i]);
T[]=build(,n);
map<int,int>mp;
for ( int i=;i<=n;i++ )
{
if ( mp.find(a[i])!=mp.end() )
{
int tmp=update(T[i-],mp[a[i]],-);
T[i]=update(tmp,i,);
}
else T[i]=update(T[i-],i,);
mp[a[i]]=i;
}
scanf("%d",&q);
while ( q-- )
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(T[r],l));
}
}
return ;
} SPOJ3267
4.(ZOJ2112)http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112
题意:给定一串序列,有两种操作,一种是求区间[l,r]第k大,另外一种是将a[i]=t
带修改的主席树
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=;
const int maxm=;
int n,q,m,tot;
int a[maxn],t[maxn];
int T[maxn],lson[maxm],rson[maxm],c[maxm];
int S[maxn];
struct Query{
int kind;
int l,r,k;
}query[]; void init_hash(int k)
{
sort(t+,t+k+);
m=unique(t+,t+k+)-(t+);
} int hash_(int x)
{
return lower_bound(t+,t+m+,x)-t;
} int build(int l,int r)
{
int root=tot++;
c[root]=;
if ( l!=r )
{
int mid=(l+r)/;
lson[root]=build(l,mid);
rson[root]=build(mid+,r);
}
return root;
} int update(int root,int pos,int val)
{
int rt=tot++,tmp=rt;
c[rt]=c[root]+val;
int l=,r=m;
while ( l<r )
{
int mid=(l+r)/;
if ( pos<=mid )
{
lson[rt]=tot++;rson[rt]=rson[root];
rt=lson[rt];root=lson[root];
r=mid;
}
else
{
rson[rt]=tot++;lson[rt]=lson[root];
rt=rson[rt];root=rson[root];
l=mid+;
}
c[rt]=c[root]+val;
}
return tmp;
} int lowbit(int x)
{
return x&(-x);
} int used[maxn];
void add(int x,int pos,int val)
{
while ( x<=n )
{
S[x]=update(S[x],pos,val);
x+=lowbit(x);
}
} int sum(int x)
{
int ret=;
while ( x> )
{
ret+=c[lson[used[x]]];
x-=lowbit(x);
}
return ret;
} int Q(int left,int right,int k)
{
int lrt=T[left];
int rrt=T[right];
int l=,r=m;
for ( int i=left;i>;i-=lowbit(i)) used[i]=S[i];
for ( int i=right;i>;i-=lowbit(i)) used[i]=S[i];
while ( l<r )
{
int mid=(l+r)/;
int tmp=sum(right)-sum(left)+c[lson[rrt]]-c[lson[lrt]];
if ( tmp>=k )
{
r=mid;
for ( int i=left;i>;i-=lowbit(i)) used[i]=lson[used[i]];
for ( int i=right;i>;i-=lowbit(i)) used[i]=lson[used[i]];
lrt=lson[lrt];
rrt=lson[rrt];
}
else
{
l=mid+;
k-=tmp;
for ( int i=left;i>;i-=lowbit(i)) used[i]=rson[used[i]];
for ( int i=right;i>;i-=lowbit(i)) used[i]=rson[used[i]];
lrt=rson[lrt];
rrt=rson[rrt];
}
}
return l;
} int main()
{
int Case;
scanf("%d",&Case);
while ( Case-- )
{
scanf("%d%d",&n,&q);
tot=;
m=;
for ( int i=;i<=n;i++ )
{
scanf("%d",&a[i]);
t[++m]=a[i];
}
char op[];
for ( int i=;i<q;i++ )
{
scanf("%s",op);
if ( op[]=='Q' )
{
query[i].kind=;
scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k);
}
else
{
query[i].kind=;
scanf("%d%d",&query[i].l,&query[i].r);
t[++m]=query[i].r;
}
}
init_hash(m);
T[]=build(,m);
for ( int i=;i<=n;i++ )
{
int pos=hash_(a[i]);
T[i]=update(T[i-],pos,);
}
for ( int i=;i<=n;i++ ) S[i]=T[];
for ( int i=;i<q;i++ )
{
if ( query[i].kind== ) printf("%d\n",t[Q(query[i].l-,query[i].r,query[i].k)]);
else
{
add(query[i].l,hash_(a[query[i].l]),-);
add(query[i].l,hash_(query[i].r),);
a[query[i].l]=query[i].r;
}
}
}
return ;
} ZOJ2112
5.(HDOJ4348)http://acm.hdu.edu.cn/showproblem.php?pid=4348
题意:给出一段长度为n的序列,有4种操作。初始时,时间戳=0
a.C l r d [l,r]区间内的数+d,时间戳++
b.Q l r 求当前时间戳下[l,r]区间的和
c.H l r t 求时间戳=t下[l,r]区间的和
d.B t 时间戳=t
分析:推荐两个讲解较为详细的博客https://blog.csdn.net/glqac/article/details/45103859
https://blog.csdn.net/kirito16/article/details/47266801
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+;
const int maxm=3e6+;
int n,q,tot;
int a[maxn];
int T[maxn],lson[maxm],rson[maxm];
ll sum[maxm],add[maxm]; int build(int l,int r)
{
int root=tot++;
add[root]=;
if ( l!=r )
{
int mid=(l+r)/;
lson[root]=build(l,mid);
rson[root]=build(mid+,r);
}
else
{
scanf("%lld",&sum[root]);
return root;
}
sum[root]=sum[lson[root]]+sum[rson[root]];
return root;
} void pushup(int rt,int len)
{
sum[rt]=sum[lson[rt]]+sum[rson[rt]]+add[lson[rt]]*(len-len/)+add[rson[rt]]*(len/);
} int A,B;
ll val; int update(int root,int l,int r)
{
int rt=tot++;
add[rt]=add[root];
if ( A<=l && r<=B )
{
sum[rt]=sum[root];
add[rt]=add[root]+val;
lson[rt]=lson[root];
rson[rt]=rson[root];
return rt;
}
int mid=(l+r)/;
if ( A<=mid ) lson[rt]=update(lson[root],l,mid);
else lson[rt]=lson[root];
if ( B>mid ) rson[rt]=update(rson[root],mid+,r);
else rson[rt]=rson[root];
pushup(rt,r-l+);
return rt;
} ll query(int root,int l,int r,ll add_)
{
if ( A<=l && r<=B ) return sum[root]+(add_+add[root])*(r-l+);
ll ans=;
int mid=(l+r)/;
if ( A<=mid ) ans+=query(lson[root],l,mid,add[root]+add_);
if ( B>mid ) ans+=query(rson[root],mid+,r,add[root]+add_);
return ans;
} int main()
{
char op[];
int now,Case=;
while ( scanf("%d%d",&n,&q)!=EOF )
{
if ( Case!= ) printf("\n");
Case++;
tot=;
T[]=build(,n);
now=;
while ( q-- )
{
ll ans;
int k;
scanf("%s",op);
if ( op[]=='C' )
{
scanf("%d%d%lld",&A,&B,&val);
T[now+]=update(T[now],,n);
now++;
}
else if ( op[]=='Q' )
{
scanf("%d%d",&A,&B);
ans=query(T[now],,n,);
printf("%lld\n",ans);
}
else if ( op[]=='H' )
{
scanf("%d%d%d",&A,&B,&k);
ans=query(T[k],,n,);
printf("%lld\n",ans);
}
else if ( op[]=='B' )
{
scanf("%d",&k);
now=k;
tot=T[now+];
}
}
}
return ;
} HDOJ4348
主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)的更多相关文章
- 少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小
少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写 ...
- SPOJ_10628_Count_on_a_Tree_(主席树+Tarjan)
描述 http://www.spoj.com/problems/COT/ 给出一棵n个节点的树,树上每一个节点有权值.m次询问,求书上u,v路径中第k小的权值. COT - Count on a tr ...
- 【洛谷 P3168】 [CQOI2015]任务查询系统(主席树)
题目链接 被自己的sb错误调到自闭.. 主席树的进阶应用. 把\(P_i\)离散化一下,得到每个\(P_i\)的排名,然后建一棵维护\(m\)个位置的主席树,每个结点记录区间总和和正在进行的任务数. ...
- BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】
任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec Memory ...
- 【STSRM12】夏令营(分治决策单调+主席树)
[题意]n个数字分成k段,每一段的价值是段内不同数字的个数,求最大价值.n<=35000,k<=50. [算法]分治决策单调+主席树(可持久化线段树) [题解] f[i][j]表示前i天分 ...
- 【bzoj4408】[Fjoi 2016]神秘数 主席树
题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+1 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- 【BZOJ2588】Count on a tree 题解(主席树+LCA)
前言:其实就是主席树板子啦……只不过变成了树上的查询 -------------------------- 题目链接 题目大意:求树上$u$到$v$路径第$k$大数. 查询静态区间第$k$大肯定是用主 ...
- 220722 T4 求和 /P4587 [FJOI2016]神秘数 (主席树)
好久没打主席树了,都忘了怎么用了...... 假设我们选了一些数能构成[0,x]范围内的所有值,下一个要加的数是k(k<=x+1),那么可以取到[0,x+k]内的所有取值,所以有一种做法: 对于 ...
随机推荐
- 关于play!的attachments.path配置、以及关于Form表单上传请求的认识
相关链接 form表单提交multipart/form-data的请求分析:http://blog.csdn.net/five3/article/details/7181521.http://blog ...
- uniqid() 函数 和 microtime()函数
uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.语法 uniqid(prefix,more_entropy) 参数 描述prefix 可选.为 ID 规定前缀.如果 ...
- 阿里云、宝塔、wordpress建站
1 阿里云 购买一个学生机就行啦 2 宝塔 2.1 更改阿里云的镜像 技巧01:先关掉阿里云之前的镜像 技巧02:到镜像市场中寻找宝塔的镜像资源 2.2 配置安全组 宝塔的控制面板需要开通端口 888 ...
- C语言-郝斌笔记-003数据类型
基本类型数据 整数 整型 —— int --4字节 短整型 —— short int ——2字节 长整型 —— long int ——8字节 浮点数[实 ...
- 后台执行UNIX/Linux命令和脚本的五种方法
hiveserver 后台启动 nohup "${HIVE_HOME}"/bin/hive --service hiveserver2 & 1. 使用&符号在后台执 ...
- bzoj4391 [Usaco2015 dec]High Card Low Card
传送门 分析 神奇的贪心,令f[i]表示前i个每次都出比对方稍微大一点的牌最多能赢几次 g[i]表示从i-n中每次出比对方稍微小一点的牌最多赢几次 ans=max(f[i]+g[i+1]) 0< ...
- Excel课程学习第三课排序与替换
一.排序 1.简单排序 点到某一个单元格,然后选择排序,就可以按照相应的顺序来排序. 2.自定义排序 按照重要性条件来排序 也可以按照重要性从轻到重挨个排序. 3.按颜色排序 4. 按照中文数字排序, ...
- IntelliJ+AntBuild+Tomcat实现Maven站点的热部署
这段时间要研究WebGL技术,做一下三维建模项目,涉及到较多的前端编码.eclipse编译器那令人着急的编码提示功能,以及丑恶的界面对项目的开展造成了一定的阻碍.为解决这个问题,转向IntelliJ ...
- Cookie seesion 赋值
后台赋值: Session["uid"] = userid;//后台 后台取值: Label1.Text = Session["userid"].ToStrin ...
- 在GridView控件FooterTemplate内添加记录
在GridView控件FooterTemplate内添加记录,想实现这个功能,有几点要清楚的,这个添加铵钮是在FooterTemplate内,还是在GridView控件外部,位置不同,某些处理逻辑会有 ...