原hdu 2665 Kth number

题意

给\(n\)个数和\(m\)次查询,每个查询包含区间\([x,y]\),求区间内第\(K\)大的数

思路

可持久化线段树,即主席树,第一次建立一个空的线段树,使用\(root\)下标表示访问第几次时间,数据离散化后。注意下标从1开始。
注意\(cnt\)可能是乱序的,但是\(root\)控制时间区间,即表示时间\(i\)的根节点为\(nodes[root[i]]\),\(nodes\)的\(l\)和\(r\)控制树的左右关系。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct{int l,r,sum;
}NODE;NODE nodes[20*MAXN];
int root[MAXN],a[MAXN],b[MAXN];
int n,m,cnt,p;int getid(int x)
{//离散化 return lower_bound(b+1,b+1+p,x)-b;
}
void build(int l,int r,int &cur)
{//建立空树 nodes[cur].sum=nodes[cur].l=nodes[cur].r=0;cur=++cnt;if(l==r)return;int mid=(l+r)>>1;build(l,mid,nodes[cur].l);build(mid+1,r,nodes[cur].r);
}
void update(int l,int r,int &cur,int pre,int pos)
{cur=++cnt;//表示新开的节点 nodes[cur].l=nodes[pre].l;nodes[cur].r=nodes[pre].r;nodes[cur].sum=nodes[pre].sum+1;//记录该点该时间之前有多少的数字 if(l==r)return ;int mid=(l+r)>>1;//每次按照pos的值插入到1~p的范围中 if(pos<=mid)update(l,mid,nodes[cur].l,nodes[pre].l,pos);else update(mid+1,r,nodes[cur].r,nodes[pre].r,pos);
}
int query(int l,int r,int x,int y,int key)
{if(l==r)return l;int mid=(l+r)>>1;int sum=nodes[nodes[y].l].sum-nodes[nodes[x].l].sum;//时间区间内个数 if(key<=sum)//查找右区间 return query(l,mid,nodes[x].l,nodes[y].l,key);else//查找左区间 return query(mid+1,r,nodes[x].r,nodes[y].r,key-sum);
}
void start()
{int x,y,k;memset(root,0,sizeof(root));cnt=0;FOR2(i,1,n){cin>>a[i];b[i]=a[i];}cnt=0;sort(b+1,b+n+1);//离散化 p=unique(b+1,b+n+1)-b-1;//数据范围 build(1,p,root[0]); //建立时间点为0 的空树 FOR2(i,1,n)//i表示时间 ,按时间插入a[i]元素到线段树 update(1,p,root[i],root[i-1],getid(a[i])); //按照a[i]在b[i]中的大小插入到不同位置 while(m--){cin>>x>>y>>k;//k=y-x-k+2;第K大和第K小的差别 cout<<b[query(1,p,root[x-1],root[y],k)]<<endl;//区间第K大就是求 时间区间的第K大 }
}
int main()
{int t;cin>>t;while(t--){memset(root,0,sizeof(root));cin>>n>>m;start();}
}

原hdu 4348 To the moon

题意

区间和线段树的可持久化,典型板子题,C表示区间加,Q表示区间查询,H表示区间查询第t时间的值,B表示返回第t时间,之后无法在前进。

基本思路

首先,需要学会基本的懒节点标记的区间和线段树,然后改,具体看代码,就是加了一层root时间节点
数组一定要开到25W左右,20W以下会爆越界错!不能开太大(超过28W,像我用结构体没空间优化),就会爆内存T_T

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct {int l,r;ll w,laz;
}NODE; NODE nodes[2500010];
int n,m,root[MAXN],cnt,x,y,d,t,now,num;
ll ans;int build(int l,int r)
{int cur;cur=num++;nodes[cur].l=nodes[cur].r=nodes[cur].w=nodes[cur].laz=0;if(l==r){cin>>nodes[cur].w;return cur;}int mid=(l+r)>>1;nodes[cur].l=build(l,mid);nodes[cur].r=build(mid+1,r);nodes[cur].w=nodes[nodes[cur].l].w+nodes[nodes[cur].r].w;//递归建树 return cur;//返回节点坐标
}int update(int pre,int x,int y,int l,int r,int d)
{int cur=num++;nodes[cur]=nodes[pre];nodes[cur].w+=d*(min(y,r)-max(x,l)+1);if(x<=l&&r<=y){nodes[cur].laz+=d;//懒节点,建议使用返回值的函数 return cur;}int mid=(l+r)/2;if(x<=mid){//左区间查询 nodes[cur].l=update(nodes[cur].l,x,y,l,mid,d);}if(y>mid){//右区间查询 nodes[cur].r=update(nodes[cur].r,x,y,mid+1,r,d);}return cur;//返回节点坐标
}ll query(int cur,int x,int y,int l,int r)
{ll res=nodes[cur].laz*(min(y,r)-max(x,l)+1);//懒节点不用下传,这是返回函数的好处,不返回值的函数需要每次修改节点的w和子节点的laz标志 if(x<=l&&r<=y){return nodes[cur].w;}int mid=(l+r)/2;if(x<=mid)res+=query(nodes[cur].l,x,y,l,mid);if(y>mid)res+=query(nodes[cur].r,x,y,mid+1,r);return res;
}int main()
{bool flag=false;while(cin>>n>>m){if(flag)cout<<endl;else flag=true;memset(root,0,sizeof(root));memset(nodes,0,sizeof(nodes));num=now=0;root[now]=build(1,n);while(m--){char op;cin>>op;while(op=='\n')cin>>op;if(op=='C'){cin>>x>>y>>d;now++;//线段树时间坐标 root[now]=update(root[now-1],x,y,1,n,d);}if(op=='Q'){cin>>x>>y;cout<<query(root[now],x,y,1,n)<<endl;}if(op=='H'){ cin>>x>>y>>t;cout<<query(root[t],x,y,1,n)<<endl;}if(op=='B'){cin>>now;}}}return 0;
}

原hdu 6278 Just h-index

题意

与hdu 2665 类似,查找区间内第\(K\)小的数\(a_k\),使得满足\(a_k-1<=\){大于\(a_k-1\)的个数}

基本思路

二分查找第K小,即mid,离散化查询第K-1个数,使得该数满足条件 。关键在于二分

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct{int l,r;ll w;
}NODE;NODE nodes[24*MAXN];
int root[24*MAXN],num,now,n,q,p;
ll arr[MAXN],b[MAXN];
int getid(ll x)
{return lower_bound(b,b+p,x)-b+1;
}
void build(int l,int r,int &cur)
{//建立空树 nodes[cur].l=nodes[cur].r=nodes[cur].w=0;num++;cur=num;if(l==r)return  ;int mid=(l+r)>>1;build(l,mid,nodes[cur].l);build(mid+1,r,nodes[cur].r);
}
void update(int l,int r,int &cur,int pre,int pos)
{num++;//建立新节点cur=num;nodes[cur].l=nodes[pre].l;nodes[cur].r=nodes[pre].r;nodes[cur].w=nodes[pre].w+1;if(l==r)return;int mid=(l+r)>>1;if(pos<=mid)update(l,mid,nodes[cur].l,nodes[pre].l,pos);else update(mid+1,r,nodes[cur].r,nodes[pre].r,pos);
}int query(int l,int r,int x,int y,int key)
{if(l==r)return l;int mid=(l+r)>>1;int c=nodes[nodes[y].l].w-nodes[nodes[x].l].w;//区间个数 if(key<=c)return query(l,mid,nodes[x].l,nodes[y].l,key);//左区间else return query(mid+1,r,nodes[x].r,nodes[y].r,key-c);//右区间
}
void start()
{p=num=now=0;FOR(i,0,n){cin>>arr[i];b[i]=arr[i];}sort(b,b+n);p=unique(b,b+n)-b;//离散化 build(1,p,root[0]);FOR(i,0,n)update(1,p,root[i+1],root[i],getid(arr[i]));while(q--){int x,y;cin>>x>>y;int l=1,r=y-x+1,rr=r,ans=1;//l r表示查询的区间大小,确定mid while(l<=r){int mid=(l+r)>>1;int t=query(1,p,root[x-1],root[y],mid);//求区间第mid大的数
//          cout<<"mid="<<mid<<"t="<<t<<"b="<<b[t-1]<<endl;if(b[t-1]>=rr-mid+1) {ans=rr-mid+1;r=mid-1; }else l=mid+1;}cout<<ans<<endl;}
}
int main()
{while(cin>>n>>q){start();}return 0;
}

转载于:https://www.cnblogs.com/tldr/p/11246857.html

CSU-ACM集训-模板-主席树相关推荐

  1. P3899 [湖南集训]谈笑风生 主席树解决二维数点

    传送门 文章目录 题意: 思路: 题意: 思路: 由于a,ba,ba,b都比ccc厉害,那么a,ba,ba,b一定是某个是某个的祖先.那么就分为两种情况了: (1)(1)(1) bbb在aaa上面,约 ...

  2. 模板—主席树(待修改)

    这个有点复杂,按理应该写写的--下次再说吧 #include<iostream> #include<cstdio> #include<algorithm> usin ...

  3. 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间=k的个数)...

    取板粗   好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...

  4. 解题报告:P3834 【模板】可持久化线段树 2(主席树)详解

    P3834 [模板]可持久化线段树 2(主席树) 题解 P3834 [[模板]可持久化线段树 2(主席树)] 1)静态求第k大数 可持久化线段树,不能用堆的方法存子结点了,所以用指针l表示左儿子r表示 ...

  5. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

  6. P3834 【模板】可持久化线段树 1(主席树)

    传送门 如标题,主席树模板 稍微介绍一下主席树.. 主席树是很多个线段树的结合体 利用了单点修改不会更新太多节点的结论(反正这一题是这样..),后一个线段树借用前面线段树的节点,而对于更新的节点才开一 ...

  7. 【洛谷】P3919 【模板】可持久化线段树(主席树)

    题目 传送门:QWQ 分析 主席树的模板,囤着 代码 #include <bits/stdc++.h> using namespace std; const int N=1000010; ...

  8. 洛谷 - P3899 [湖南集训]谈笑风生(dfs序+主席树/二维数点)

    题目链接:点击查看 题目大意:设 TTT 为一棵有根树,我们做如下的定义: 设 aaa 和 bbb 为 TTT 中的两个不同节点.如果 aaa 是 bbb 的祖先,那么称"aaa 比 bbb ...

  9. #6073. 「2017 山东一轮集训 Day5」距离(树链剖分 + 永久标记主席树)

    #6073. 「2017 山东一轮集训 Day5」距离 给定一颗有nnn个节点带边权的树,以及一个排列ppp,path(u,v)path(u, v)path(u,v)为u,vu, vu,v路径上的点集 ...

最新文章

  1. oracle之 手动创建 emp 表 与 dept 表
  2. 三份研究报告,聚焦 AI 的三大主要话题
  3. jQuery核心函数的使用总结
  4. 使用 IntelliJ IDEA 查看类图,内容极度舒适
  5. Linux日常命令使用记录
  6. LightSwitch中的权限
  7. 自适应阈值算法(大津阈值法)
  8. 电子商务数据挖掘python案例_精心整理!9个 Python 实用案例分享!
  9. (06)Verilog HDL组合逻辑:always
  10. WPF之Binding的三种简单写法
  11. 【数学建模】评价模型
  12. 一般纳税人与小规模纳税人有什么区别
  13. 计算机程序设计能力考试 PAT 简介(浙大)
  14. 一个字的伤感网名又是一个伤感的故事
  15. android添加adb命令行,Android—adb命令
  16. 软件工程——数据流图
  17. linux7配置dns服务,RHEL7 DNS配置
  18. python 如何添加国内源_pip和conda添加国内清华镜像源(亲测有效)
  19. 计算机主板尺寸,电脑主板大中小三个等级的尺寸是多少?
  20. 4G物联网卡的几点优势

热门文章

  1. java制作风车图像的main方法_创意图形的绘制 会转的风车
  2. matlab libjli.so,error while loading shared libraries: libjli.so 问题解决
  3. MySQL不同数据类型如何表示_MySQL系列(二)--数据类型
  4. dhcp协议_记录一次DHCP协议的学习过程
  5. 如何计算像素当量_「轴承知识」如何通过静承载能力选择轴承
  6. 极简主义︱使用Turicreate进行快速图像分类迁移训练与预测(六)
  7. R语言︱决策树族——随机森林算法
  8. 高并发下的HashMap
  9. Analytic Functions in Oracle 8i and 9i
  10. 再记AE与AO的区别与联系