数据结构方面常用模板总结,大多数代码摘自网络,个人整理总结

string:

    任意进制转换:itoa(int n,char* s,int r)  //将10进制n转换为r进制并赋给s流:#include<sstream>stringstream stream;   //创建名为stream的流stream.clear   //重复使用必须清空string a,str;stream(a);             //将字符串a放入流while(a>>str)       //将a流入str中,以空格为拆分进行输出cout<<str<<endl;迭代器:string::iterator it  //创建名为it的迭代器反转:reverse(s.begin(), s.end());   //原地反转s1.assign(s.rbegin(), s.rend());   //反转并赋给s1大小写转换:transform(s.begin(), s.end(), s.begin(), ::toupper);transform(s.begin(), s.end(), s.begin(), ::tolower);类型转换:string ->int : string s("123");int i = atoi(s.c_str());int -> string: int a;stringstream(s) >> a;子串:string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串更改:s.assign(str); //直接s.assign(str,1,3);//如果str是”iamangel” 就是把”ama”赋给字符串s.assign(str,2,string::npos);//把字符串str从索引值2开始到结尾赋给ss.assign(“gaint”); //不说s.assign(“nico”,5);//把’n’ ‘I’ ‘c’ ‘o’ ‘\0’赋给字符串s.assign(5,’x’);//把五个x赋给字符串删除:s.erase(13);//从索引13开始往后全删除s.erase(7,5);//从索引7开始往后删5个iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置  iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置查找:int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置。删除所有特定字符:str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

集合set:

  头文件:#include<set>声明:set<T>s;迭代器:set<T>::iterator;插入:A.insert("Tom");删除:A.erase("Tom");    只支持正向迭代器查找:A.count("Tom");遍历:set<string>::iterator it;for(it=A.begin();it!=A.end();it++)cout<<(*it);正向: A.begin(); 返回集合中第一个元素的迭代器A.end(); 返回集合中最后一个元素下一位置的迭代器反向:set<T>:: reverse_iterator;A.rbegin(); 返回集合中最后一个元素的反向迭代器A.rend(); 返回集合中第一个元素前一位置的反向迭代器清空:A.clear();取并:set_union(A.begin(),A.end(),B.begin(),B.end(),inserter( C , C.begin() ) );  将A集合与B集合取并后存入C集合,要去A,B必须有序取交:set_intersection(A.begin(),A.end(),B.begin(),B.end(),inserter( C , C.begin() ));   取交集,同上

映射map:

  头文件:#include<map>声明:map<T1,T2>m;插入:A.insert(pari<string,int>("Tom",1));A["Tom"]=1;访问:cout<<A["Tom"];查找:A.count("Tom")若存在返回1,否则返回0遍历:map<string,int>::iterator it;for(it=A.begin();it!=A.end();it++)cout<<it->first<<it->second;清空:A.clear();删除:A.erase(it);

优先队列:

  头文件:#include<queue>默认从大到小排列声明:普通优先队列:priority_queue<int>Q;从小到大优先队列:priority_queue<int,vector<int>,greater<int> >Q;对结构体应用优先队列:struct Node
{int x,y,val;friend bool operator < (node n1,node n2){if(n1.val==n2.val)return n1.x>n2.x;return n1.val<n2.val;    //和正常不同,"<"为从大到小,">"为从小到大}
};
priority_queue<node>Q

单调栈:

https://blog.csdn.net/wubaizhe/article/details/70136174
利用单调栈,可以找到从左/右遍历第一个比它小/大的元素的位置.由此也可知道该区间上数的个数O(n)
可统计出a[i]~a[n],以i为起点的单调序列长度,从后向前建立单调栈,常做预处理用
一个元素向左遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,若栈为空,则说明不存在这么一个数。然后将此元素的下标存入栈,就能类似迭代般地求解后面的元素

#include <iostream>
#include <stack>
using namespace std;stack<int>s;
int n;
int ans[N];          //ans[i],表示第i个元素,向左遍历,第一个比它小的元素的位置
void getans(int a[])
{for(int i=1;i<=n;i++){while(s.size() && a[s.top()]>=a[i]) s.pop();if(s.empty()) ans[i]=0;else ans[i]=s.top();s.push(i);}
}

单调队列:

整理归纳单调队列的定义:
1、维护区间最值;
2、去除冗杂状态;
3、保持队列单调(最大值是单调递减序列,最小值是单调递增序列);
4、最优选择在队首。
在维护好一个 区间正确、严格递减 的单调递减队列后,队列头就是当前区间的最大值了

整理归纳单调队列的使用方法:
1、维护队首(对于上题就是如果你已经是当前的m个之前那你就可以被删了) ;
2、在队尾插入(每插入一个就要从队尾开始往前去除冗杂状态) ;
3、取出需要的最优解(队列头的值即是);
4、借助最优解,得到目前所求的最优解(通常此处插入DP方程)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[200000];
struct node
{int x,p;node(){}node(int xx,int pp){x=xx;p=pp;}
}list[200000];
int main()
{int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);int head=1,tail=1;list[1]=node(a[1],1);for(int i=2;i<=n;i++){while(head<=tail&&list[tail].x<=a[i]) tail--;//删尾list[++tail]=node(a[i],i);//得到最优解并插入while(i-list[head].p>=m) head++;//去头if(i>=m) printf("%d\n",list[head]);}return 0;
}

二分查找:

只能对有序数列使用,内部通过二分查找实现

  lower_bound(a,a+n,m)://返回数组a中,0~n里第一个大于等于m的指针int pos=lower_bound(a,a+n,m)-a://返回数组a中,0~n里第一个大于等于m的位置upper_bound(a,a+n,m)://返回数组a中,0~n里第一个大于m的指针int pos=upper_bound(a,a+n,m)-a://返回数组a中,0~n里第一个大于m的位置lower_bound(seq2, seq2+6, 7, greater<int>())://加greater<int>()后,lower变小于等于,upper变小于

排列:

  头文件:#include<algorithm>next_permutation(a,a+3)   //求数组a中前3个元素的下一个排列 prev_permutation(a,a+3)   //求数组a中前3个元素的前一个排列a可为普通数组,string,vector......求1-10的第10个排列a[10]={1,2,3,4,5,6,7,8,9,10};for(int i=1;i<k;i++)next_permutation(a,a+10);for(int i=0;i<10;i++)cout<<a[i]<<" ";

树状数组:

巧妙利用二进制性质,实现在log(n)对区间和的查询,修改操作
#include <iostream>
#include <string.h>
using namespace std;
const int N=100050;
int c[N],ans[N];      //c[n]表示a[1~n]的和,a数组省略
int lowbit(int x)       //求2^k
{ return x & -x;
}
int getsum(int n)   //区间查询,求a[1~n]的和
{int res = 0;while(n>0){res+=c[n];n=n-lowbit(n);}return res;
}
int change(int x)  //单点更新,将a[x]的值加1
{while(x<=N){c[x]++;x+=lowbit(x);}
}
int main()
{int n;cin>>n;memset(c,0,sizeof(c));memset(ans,0,sizeof(ans));for(int i=0;i<n;i++){int x,y;cin>>x>>y;x++;ans[getsum(x)]++;change(x);}for(int i=0;i<n;i++)cout<<ans[i]<<endl;return 0;
}

线段树:

 单点操作,区间查询:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
#define INF 10000000
#define lson l,mid,rt<<1      //左儿子
#define rson mid+1,r,rt<<1|1  //右儿子
const int maxn = 222222;
struct Node{  int Max,Min;  //区间的最大值和最小值  int sum;      //区间的和
}stree[maxn<<2];
void up(int rt){  //更新该区间的最值与和  stree[rt].Max=max(stree[rt<<1].Max,stree[rt<<1|1].Max);  stree[rt].Min=min(stree[rt<<1].Min,stree[rt<<1|1].Min);  stree[rt].sum=stree[rt<<1].sum+stree[rt<<1|1].sum;
}
void build(int l,int r,int rt){  //在结点i上建立区间为[l,r]  if(l==r){                    //叶子结点  int num;  scanf("%d",&num);  stree[rt].Max=stree[rt].Min=stree[rt].sum=num;  return ;  }  int mid=(l+r)>>1;  build(lson); //建立左儿子  build(rson); //建立右儿子  up(rt);      //更新
}
int querymax(int a,int b,int l,int r,int rt){  //求区间[a,b]的最大值  if(a<=l&&r<=b){  //如果全包含,直接取区间最大值  return stree[rt].Max;  }  int mid = (r+l)>>1;  int ret = -INF;  if(a<=mid) ret=max(ret,querymax(a,b,lson));//如果左端点在中点的左边,找出左区间的最大值  if(mid<b) ret=max(ret,querymax(a,b,rson));//如果右端点在中点的右边,找出右区间(以及左区间)的最大值  return ret;
}
int querymin(int a,int b,int l,int r,int rt){  //求区间[a,b]的最小值  if(a<=l&&r<=b){  //如果全包含,直接取区间最小值  return stree[rt].Min;  }  int mid = (r+l)>>1;  int ret = INF;  if(a<=mid) ret=min(ret,querymin(a,b,lson));//如果左端点在中点的左边,找出左区间的最小值  if(mid<b) ret=min(ret,querymin(a,b,rson)); //如果右端点在中点的右边,找出右区间(以及左区间)的最小值  return ret;
}
int querysum(int a,int b,int l,int r,int rt){  //求区间[a,b]的和(a,b的值相同时为求单点的值)  if(a<=l&&r<=b){ //如果全包含,直接取区间的和  return stree[rt].sum;  }  int mid = (r+l)>>1;  int ret=0;  if(a<=mid) ret+=querysum(a,b,lson);  if(mid<b) ret+=querysum(a,b,rson);  return ret;
}
void uppoint(int a,int b,int l,int r,int rt){  //单点替换,把第a个数换成b  if(l==r){  stree[rt].Max=stree[rt].Min=stree[rt].sum=b;  return ;  }  int mid =(r+l)>>1;  if(a<=mid)uppoint(a,b,lson);  else uppoint(a,b,rson);  up(rt);
}
void upadd(int a,int b,int l,int r,int rt){  //单点增减,把第a个数增减b  if(l==r){  stree[rt].sum=stree[rt].sum+b;  stree[rt].Max=stree[rt].Max+b;  stree[rt].Min=stree[rt].Min+b;  return ;  }  int mid=(l+r)>>1;  if(a<=mid) upadd(a,b,lson);  else upadd(a,b,rson);  up(rt);
}
int main()
{  //freopen("F:\\11.txt","r",stdin);  int n,q;  while(~scanf("%d%d",&n,&q)){  build(1,n,1);//build(l,r,rt);  while(q--){  char op[10];  int a,b;  scanf("%s%d%d",op,&a,&b);  if(op[0]=='X'){//求区间[a,b]的最大值  printf("%d\n",querymax(a,b,1,n,1));//querymax(int a,int b,int l,int r,int rt);  }  else if(op[0]=='N'){//求区间[a,b]的最小值  printf("%d\n",querymin(a,b,1,n,1));//querymin(int a,int b,int l,int r,int rt);  }  else if(op[0]=='U'){//单点替换,把第a个数换成b  uppoint(a,b,1,n,1);//uppoint(int a,int b,int l,int r,int rt);  }  else if(op[0]=='S'){//求区间[a,b]的和(a,b的值相同时为求单点的值)  printf("%d\n",querysum(a,b,1,n,1));//querysum(int a,int b,int l,int r,int rt);  }  else if(op[0]=='A'){//单点增加,把第a个数增加b  upadd(a,b,1,n,1);  }  else if(op[0]=='E'){//单点减少,把第a个数减少b  upadd(a,-b,1,n,1);  }  }  }  return 0;
}  

区间替换,区间查询:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100100;
const int INF=0x7fffffff;
using namespace std;
int lazy[maxn<<2];
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];
void PushUp(int rt) { //由左孩子、右孩子向上更新父节点SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}
void PushDown(int rt,int m) { //向下更新if (lazy[rt]) { //懒惰标记lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];MAX[rt<<1]=MAX[rt<<1|1]=lazy[rt];MIN[rt<<1]=MIN[rt<<1|1]=lazy[rt];lazy[rt] = 0;}
}
//所有的l,r,rt  带入1,n,1
void build(int l,int r,int rt) { //初始化建树lazy[rt] = 0;if (l== r) {SUM[rt]=MAX[rt]=MIN[rt]=0;  //初始化为0的建树/*scanf("%d",&SUM[rt]);  //边读入边建树的方法MAX[rt]=MIN[rt]=SUM[rt];*/return ;}int m = (l + r) >> 1;build(lson);build(rson);PushUp(rt);
}
void update(int L,int R,int v,int l,int r,int rt) { //将L~R区间的值置为v//if(L>l||R>r) return;if (L <= l && r <= R) {lazy[rt] = v;SUM[rt] = v * (r - l + 1);MIN[rt] = v;MAX[rt] = v;//printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);return ;}PushDown(rt , r - l + 1);int m = (l + r) >> 1;if (L <= m) update(L , R , v , lson);if (R > m) update(L , R , v , rson);PushUp(rt);
}
int querySUM(int L,int R,int l,int r,int rt) {  //求区间L~R的和if (L <= l && r <= R) {//printf("%d\n", sum[rt]);return SUM[rt];}PushDown(rt , r - l + 1);int m = (l + r) >> 1;int ret = 0;if (L <= m) ret += querySUM(L , R , lson);if (m < R) ret += querySUM(L , R , rson);return ret;
}
int queryMIN(int L,int R,int l,int r,int rt) {  //求区间L~R的最小值if (L <= l && r <= R) {//printf("%d\n", sum[rt]);return MIN[rt];}PushDown(rt , r - l + 1);int m = (l + r) >> 1;int ret = INF;if (L <= m) ret = min(ret, queryMIN(L , R , lson));if (m < R) ret = min(ret,queryMIN(L , R , rson));return ret;
}
int queryMAX(int L,int R,int l,int r,int rt) {  //求区间L~R的最大值if (L <= l && r <= R) {//printf("%d\n", sum[rt]);return MAX[rt];}PushDown(rt , r - l + 1);int m = (l + r) >> 1;int ret = -INF;if (L <= m) ret = max(ret, queryMAX(L , R , lson));if (m < R) ret = max(ret,queryMAX(L , R , rson));return ret;
}
int main() {int  n , m;char str[5];while(scanf("%d%d",&n,&m)) {build(1 , n , 1);while (m--) {scanf("%s",str);int a , b , c;if(str[0]=='T') {scanf("%d%d%d",&a,&b,&c);update(a , b , c , 1 , n , 1);} else if(str[0]=='Q') {scanf("%d%d",&a,&b);cout<<querySUM(a,b,1,n,1)<<endl;} else if(str[0]=='A') {scanf("%d%d",&a,&b);cout<<queryMAX(a,b,1,n,1)<<endl;} else if(str[0]=='I') {scanf("%d%d",&a,&b);cout<<queryMIN(a,b,1,n,1)<<endl;}}}return 0;
}

区间增加,区间查询:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100100;
const int INF=0x7fffffff;
using namespace std;
int lazy[maxn<<2];
int SUM[maxn<<2],MAX[maxn<<2],MIN[maxn<<2];
void putup(int rt) {SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];MAX[rt] =max(MAX[rt<<1],MAX[rt<<1|1]) ;MIN[rt] =min(MIN[rt<<1],MIN[rt<<1|1]);
}
void putdown(int rt,int m) {if (lazy[rt]) {lazy[rt<<1] += lazy[rt];lazy[rt<<1|1] += lazy[rt];SUM[rt<<1] += lazy[rt] * (m - (m >> 1));SUM[rt<<1|1] += lazy[rt] * (m >> 1);MAX[rt<<1]+=lazy[rt];MAX[rt<<1|1] +=lazy[rt];MIN[rt<<1]+=lazy[rt];MIN[rt<<1|1]+=lazy[rt];lazy[rt] = 0;}
}
//以下的 l,r,rt 都带入 1,n,1
void build(int l,int r,int rt) {  //初始化建树lazy[rt] = 0;if (l == r) {//初始化树为0的写法SUM[rt]=MAX[rt]=MIN[rt]=0;/*  //边读入边建树的写法scanf("%d",&SUM[rt]);MAX[rt]=MIN[rt]=SUM[rt];*/return ;}int m = (l + r) >> 1;build(lson);build(rson);putup(rt);
}
void update(int L,int R,int v,int l,int r,int rt) {  //将区间L~R的值增加vif (L <= l && r <= R) {lazy[rt] += v;SUM[rt] += v * (r - l + 1);MAX[rt]+=v;MIN[rt]+=v;return ;}putdown(rt , r - l + 1);int m = (l + r) >> 1;if (L <= m) update(L , R , v , lson);if (m < R) update(L , R , v , rson);putup(rt);
}
int querySUM(int L,int R,int l,int r,int rt) {  //求区间L~R的和if (L <= l && r <= R) {return SUM[rt];}putdown(rt , r - l + 1);int m = (l + r) >> 1;int ret = 0;if (L <= m) ret += querySUM(L , R , lson);if (m < R) ret += querySUM(L , R , rson);return ret;
}
int queryMAX(int L,int R,int l,int r,int rt) {  //求区间L~R的最大值if (L <= l && r <= R) {return MAX[rt];}putdown(rt , r - l + 1);int m = (l + r) >> 1;int ret = -INF;if (L <= m) ret =max(ret,queryMAX(L , R , lson)) ;if (m < R) ret =max(ret,queryMAX(L , R , rson)) ;return ret;
}
int queryMIN(int L,int R,int l,int r,int rt) {  //求区间L~R的最小值if (L <= l && r <= R) {return MIN[rt];}putdown(rt , r - l + 1);int m = (l + r) >> 1;int ret = INF;if (L <= m) ret = min(ret,queryMIN(L , R , lson));if (m < R) ret = min(ret,queryMIN(L , R , rson));return ret;
}
int main() {int n , m;int a , b , c;char str[5];scanf("%d%d",&n,&m);build(1 , n , 1);while (m--) {scanf("%s",str);if (str[0] == 'S') {scanf("%d%d",&a,&b);printf("%d\n",querySUM(a , b , 1 , n , 1));} else if(str[0]=='C') {scanf("%d%d%d",&a,&b,&c);update(a , b , c , 1 , n , 1);} else if(str[0]=='A') {scanf("%d%d",&a,&b);printf("%d\n",queryMAX(a , b , 1 , n , 1));} else if(str[0]=='I') {scanf("%d%d",&a,&b);printf("%d\n",queryMIN(a , b , 1 , n , 1));}}return 0;
}

区间求和

#include <stdio.h>
#include <iostream>
#define N 111111#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;LL add[N<<2];
LL sum[N<<2];void PushUP(int rt)
{sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}void PushDown(int rt,int m)
{if(add[rt]){add[rt<<1]+=add[rt];add[rt<<1|1]+=add[rt];sum[rt<<1]+=(m-(m>>1))*add[rt];sum[rt<<1|1]+=(m>>1)*add[rt];add[rt]=0;}
}void Build(int l,int r,int rt)
{add[rt]=0;if(l==r){scanf("%lld",&sum[rt]);return;}int m=(l+r)>>1;Build(lson);Build(rson);PushUP(rt);
}void Update(int L,int R,int c,int l,int r,int rt)
{if(L<=l&&R>=r){add[rt]+=c;sum[rt]+=(LL)c*(r-l+1);return;}PushDown(rt,r-l+1);int m=(l+r)>>1;if(L<=m)Update(L,R,c,lson);if(R>m)Update(L,R,c,rson);PushUP(rt);
}LL Query(int L,int R,int l,int r,int rt)
{if(L<=l&&R>=r)return sum[rt];PushDown(rt,r-l+1);int m=(l+r)>>1;LL ret=0;if(L<=m)   ret+=Query(L,R,lson);if(R>m)    ret+=Query(L,R,rson);return ret;
}int main()
{int m,n;scanf("%d%d",&n,&m);Build(1,n,1);while(m--){char s[5];int a,b,c;scanf("%s",s);if(s[0]=='Q'){scanf("%d%d",&a,&b);printf("%lld\n",Query(a,b,1,n,1));}else{scanf("%d%d%d",&a,&b,&c);Update(a,b,c,1,n,1);}}return 0;
}

zkw线段树:

代码简单,效率高

单点操作,区间查询:

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
const int N=50005;
int n,M,q;
int d[N*4];
void build(int n)
{for(M=1;M<n;M<<=1);for(int i=M+1;i<=M+n;i++)scanf("%d",&d[i]);for(int i=M-1;i;i--)d[i]=d[i<<1]+d[i<<1|1];//d[i]=max(d[i<<1],d[i<<1|1]);   求最值
}
void update_add(int x,int y)
{d[x+=M]+=y;x>>=1;for(;x;x>>=1)d[x]=d[x<<1]+d[x<<1|1];
}
void update_sub(int x,int y)
{d[x+=M]-=y;x>>=1;for(;x;x>>=1)d[x]=d[x<<1]+d[x<<1|1];
}
void update_change(int x,int y)
{d[x+=M]=y;for(x>>=1;x;x>>=1)d[x]=max(d[x<<1],d[x<<1|1]);
}
int query_max(int s,int t)
{int ans=-1;for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){if(~s&1)ans=max(ans,d[s^1]);if(t&1)ans=max(ans,d[t^1]);}return ans;
}
int query_sum(int s,int t)
{int ans=0;for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){if(~s&1)ans+=d[s^1];if(t&1)ans+=d[t^1];}return ans;
}
int main()
{int a,b;string str;cin>>n;build(n);while(cin>>str){if(str=="End")break;if(str=="Query"){cin>>a>>b;cout<<query(a,b)<<endl;}if(str=="Add"){cin>>a>>b;update_add(a,b);}if(str=="Sub"){cin>>a>>b;update_sub(a,b);}}return 0;
}

主席树:

每个结点都是一棵线段树,维护[1~i]的前缀信息,各操作均为O(logn)
特点:查询区间第K大;将当前版本返回之前某版本;在之前某版本上区间查询
https://blog.csdn.net/creatorx/article/details/75446472
https://blog.csdn.net/CillyB/article/details/75912440

用主席树求区间第K大问题,包含离散化:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 10;
int n, m;
int cnt;
struct node{int L, R;//分别指向左右子树int sum;//该节点所管辖区间范围内数的个数node(){sum = 0;}
}Tree[maxn * 20];
struct value{int x;//值的大小int id;//离散之前在原数组中的位置
}Value[maxn];
bool cmp(value v1, value v2)
{return v1.x < v2.x;
}
int root[maxn];//多颗线段树的根节点
int rank[maxn];//原数组离散之后的数组
void init()
{cnt = 1;root[0] = 0;Tree[0].L = Tree[0].R = Tree[0].sum = 0;
}
void update(int num, int &rt, int l, int r)
{Tree[cnt++] = Tree[rt];rt = cnt - 1;Tree[rt].sum++;if(l == r) return;int mid = (l + r)>>1;if(num <= mid) update(num, Tree[rt].L, l, mid);else update(num, Tree[rt].R, mid + 1, r);
}
int query(int i, int j, int k, int l, int r)    //查询第K小的数
{int d = Tree[Tree[j].L].sum - Tree[Tree[i].L].sum;if(l == r) return l;int mid = (l + r)>>1;if(k <= d) return query(Tree[i].L, Tree[j].L, k, l, mid);else return query(Tree[i].R, Tree[j].R, k - d, mid + 1, r);
}int query_lessKNum(int i,int j,int k,int l,int r)    //查询小于等于k的数有几个
{if(l==r) return Tree[j].sum - Tree[i].sum;int mid=(l+r)>>1;int res=0;if(k<=mid) res+=query_lessKNum(Tree[i].L,Tree[j].L,k,l,mid);else{res+=Tree[Tree[j].L].sum-Tree[Tree[i].L].sum;res+=query_lessKNum(Tree[i].R,Tree[j].R,k,mid+1,r);}return res;
}int main()
{scanf("%d%d", &n, &m);for(int i = 1; i <= n; i++){scanf("%d", &Value[i].x);Value[i].id = i;}//进行离散化sort(Value + 1, Value + n + 1, cmp);for(int i = 1; i <= n; i++){rank[Value[i].id] = i;}init();for(int i = 1; i <= n; i++){root[i] = root[i - 1];update(rank[i], root[i], 1, n);}int left, right, k;for(int i = 1; i <= m; i++){scanf("%d%d%d", &left, &right, &k);printf("%d\n", Value[query(root[left - 1], root[right], k, 1, n)].x);}return 0;
}

并查集:

int fa[N],rank[N];
void init(int n)    //初始化
{for(int i=0;i<n;i++){fa[i]=i;rank[i]=0;}
}
int find(int x)
{if(fa[x]==x)return x;elsereturn fa[x]=find(fa[x]);
}
void unite(int x,int y)
{x=find(x);y=find(y);if(x==y) return ;if(rank[x]<rank[y])fa[x]=y;else{fa[y]=x;if(rank[x]==rank[y])rank[x]++;}
}
bool same(int x,int y)
{return find(x)==find(y);
}

映射二叉堆:

利用set实现,可以在log(n)的时间进行增,删,改,查操作,利用优先级进行排序,再映射到相应内容
#define PII pair<int, int>
set<PII, greater<PII>> gheap;    // 定义了一个大根堆
set<PII, less<PII>> lheap;    // 定义了一个小根堆//pair的first储存关键字(优先级),second储存索引或内容
int keys[MAX_INDEX];  // 存储每个索引对应的内容,如果索引的范围很大,可以用 map<int, int> 来储存
//堆的插入
gheap.insert(make_pair(value, id));
//取堆顶元素
set<PII, greater<PII>>::iterator iter = gheap.begin();
cout << iter->first << " " << iter->second << endl;  // 第一个数是堆顶元素的关键字,第二个数是堆顶元素的索引
//取堆尾元素
set<PII, greater<PII>>::reverse_iterator riter = gheap.rbegin();
cout<< riter->first<<" "<<riter->second<<endl;
//删除指定元素
gheap.erase(make_pair(keys[idx], idx));
//删除堆顶元素
gheap.erase(*(gheap.begin()));
//删除堆尾元素
riter=gheap.rbegin();
int a=riter->first;
int b=riter->second;
gheap.erase(make_pair(a,b));

平衡树:

  用于动态维护数据,可求特定值的排名,特定排名的值,某值的前驱,某值的后继

Treap(树堆):

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
struct TREAP{int l,r,val,sz,recy,rd;//sz表示树的节点数,recy记录自己被重复了几次//rd表示该节点的优先级
}t[1000000];
int m,size,root,ans;
void update(int k){t[k].sz=t[t[k].l].sz+t[t[k].r].sz+t[k].recy;//更新维护
}
void left_rotate(int &k){int y=t[k].r;t[k].r=t[y].l;t[y].l=k;t[y].sz=t[k].sz;update(k);k=y;//左旋,至于这里的k=y,由于下面的递归调用,//它会一直迭代,所以无需担心会有什么错误
}
void right_rotate(int &k){int y=t[k].l;t[k].l=t[y].r;t[y].r=k;t[y].sz=t[k].sz;update(k);k=y;//右旋
}
//以下函数的调用中(int k)表示在根为k的子树中
void insert(int &k,int x){//插入操作if (k==0){//无节点时特判,//或是递归的边界,即插入叶节点++size;k=size;t[k].sz=t[k].recy=1;t[k].val=x;t[k].rd=rand();return ;//rand()生成随机的优先级,保证了期望复杂度}++t[k].sz;//每次向下找同时增加该节点1个节点数if (t[k].val==x) ++t[k].recy;//如果是相同数字,只需++recy即可else if (x>t[k].val){insert(t[k].r,x);if (t[t[k].r].rd<t[k].rd) left_rotate(k);//插入后如果违反堆性质,就进行上浮}else{insert(t[k].l,x);if (t[t[k].l].rd<t[k].rd) right_rotate(k);}
}
void del(int &k,int x){if (k==0) return ;//无节点就跳出if (t[k].val==x){if (t[k].recy>1){--t[k].recy;--t[k].sz;return ;//如果重复了,只需--recy即可}if (t[k].l*t[k].r==0) k=t[k].l+t[k].r;//如果左右儿子有为空的情况//或将其变为其儿子节点,或将其删除else if (t[t[k].l].rd<t[t[k].r].rd)right_rotate(k),del(k,x);//如果其左右儿子都有,选择优先级较大的,//保持以后的堆性质,同时将k节点下沉else left_rotate(k),del(k,x);}else if (x>t[k].val)--t[k].sz,del(t[k].r,x);//如果关键值不同,继续向下找else --t[k].sz,del(t[k].l,x);
}
int atrank(int k,int x){//寻找值为x的数的排名if (k==0) return 0;if (t[k].val==x) return t[t[k].l].sz+1;//如果找的关键字,根据BST的性质,//则其排名为左子树的大小+1else if (x>t[k].val)return t[t[k].l].sz+t[k].recy+atrank(t[k].r,x);//加上前面所有比它小的数,在右子树中找else return atrank(t[k].l,x);//如果在左子树中找的话就不用加了
}
int rerank(int k,int x){//寻找排名为x的数值if (k==0) return 0;if (x<=t[t[k].l].sz) return rerank(t[k].l,x);//如果x小于了左子树的大小,那解一定在左子树中else if (x>t[t[k].l].sz+t[k].recy)return rerank(t[k].r,x-t[k].recy-t[t[k].l].sz);//如果x大于的左子树的大小+k的重复次数,//那就在右子树中找else return t[k].val;//否则就是找到解了(包含了重复数字中)
}
void pred(int k,int x){//找前缀if (k==0) return ;if (t[k].val<x){ans=k;pred(t[k].r,x);//找到了更优的解,就替换之//而且在其右子树中不可能再有更优的了//故向其左子树中找}else pred(t[k].l,x);//否则就往右子树中找
}
void succ(int k,int x){//找后缀if (k==0) return ;if (t[k].val>x){ans=k;succ(t[k].l,x);}else succ(t[k].r,x);
}
int main(){int f,x;scanf("%d",&m);for (int i=1;i<=m;++i){scanf("%d%d",&f,&x);ans=0;if (f==1) insert(root,x);if (f==2) del(root,x);if (f==3) printf("%d\n",atrank(root,x));if (f==4) printf("%d\n",rerank(root,x));if (f==5) {pred(root,x);printf("%d\n",t[ans].val);}if (f==6) {succ(root,x);printf("%d\n",t[ans].val);}}return 0;
}

http://blog.csdn.net/lemonoil/article/details/71816386

01字典树:

求数组上一段连续数据的异或和最大是多少
int ch[32*MAX][2];
LL val[32*MAX];
int sz;
void init(){mem(ch[0],0);sz=1;
}
void inser(LL a){int u=0;for(int i=32;i>=0;i--){int c=((a>>i)&1);if(!ch[u][c]){mem(ch[sz],0);val[sz]=0;ch[u][c]=sz++;}u=ch[u][c];}val[u]=a;
}
LL query(LL a){int u=0;for(int i=32;i>=0;i--){int c=((a>>i)&1);if(ch[u][c^1]) u=ch[u][c^1];else u=ch[u][c];}return val[u];
}

转载于:https://www.cnblogs.com/floatingcloak/p/10344176.html

ACM常用模板-数据结构相关推荐

  1. 算法——常用的数据结构/模板/基础知识

    常用的数据结构/模板/基础知识 (一)c++--优先队列(priority_queue) 最大堆和最小堆的写法 (二)c++中的全排列函数next_permutation() (三)迭代器的使用 (四 ...

  2. 【Sofice小司笔记】2 算法与数据结构,各类基础及常用高级数据结构、各种搜索方法、动态规划、字符串、数论、编码学、排序等,大部分都基于java实现

    维基百科算法与数据结构 ACM模式模板: import java.io.*; import java.util.*; public class Main{public static void main ...

  3. ACM常用算法及练习

    ACM常用算法及练习 (想学请先放弃) 第一阶段:练bai经典常用算法,下面的每个算法给我打上十du到二十遍,同时自己精简zhi代码 1.最短路(Floyd.Dijstra,BellmanFord) ...

  4. html5常用模板下载网站

    html5常用模板下载网站 开创者素材.站长素材.模板之家 推荐葡萄家园素材网,他们网页模板栏目有个HTML模板,很多静态源码.应该是你所需要的. html静态页面模板 还是服饰素材啊 朋友 设计云 ...

  5. 【算法】常用的数据结构与算法

    学习了王争老师的数据结构与算法之美之后,比较有感触,他把我们常用的数据结构和算法都讲了一遍,而且讲的还不错.整理汇总一下作为笔记. 一.复杂度分析 非常重要.我们必须掌握,基本上要做到,简单代码能很快 ...

  6. 【算法基础】常用的数据结构与算法

    学习了王争老师的数据结构与算法之美之后,比较有感触,他把我们常用的数据结构和算法都讲了一遍,而且讲的还不错.整理汇总一下作为笔记. 一.复杂度分析 非常重要.我们必须掌握,基本上要做到,简单代码能很快 ...

  7. 【算法入门】动态图展示 6 个常用的数据结构,一目了然!

    数据结构的确很枯燥,尤其是初学时候,不知道到底有啥用.不过随着编码年限的增长,我们越会发现它真的很有用,巧妙的数据结构是算法高效实现的助推剂. 今天的文章不会用文字和静态图展现常用的数据结构,因为这种 ...

  8. 常用的数据结构_动态图展示 6 个常用的数据结构,一目了然

    数据结构的确很枯燥,尤其是初学时候,不知道到底有啥用.不过随着编码年限的增长,我们越会发现它真的很有用,巧妙的数据结构是算法高效实现的助推剂. 今天的文章不会用文字和静态图展现常用的数据结构,因为这种 ...

  9. 雅思作文模板.html,雅思小作文常用模板万能句大全

    雅思小作文模板--柱状图 柱状图和线型图写法一致,并且结合饼状图来写! 表格题 1. 找出值,最小值,以及一般值 2. 进行分析比较,找出近似值和相差很大的数值 常用句式 1.a is nearly ...

最新文章

  1. Single Image Dehazing via Conditional Generative Adversarial Network(CVPR2018-图像去雾)
  2. kcf跟踪算法实例整理
  3. 1.2 matlab数值数据的输出格式
  4. 【机器学习】——《机器学习实战》面试复习
  5. mysql协议重传,MySQL · 源码分析 · 网络通信模块浅析
  6. Java线程--BlockingQueue使用
  7. visual studio 按钮判断管理员和用户_用户管理的设计原则
  8. 设计模式 之 桥接模式
  9. 360团队 临时目录的原始文件不是360合法文件_谈谈腾讯电脑管家小团队版
  10. od找数据 遇到dll_OriginPro:最近比较烦,被360盯上了【数据绘图】
  11. mysql c函数大全_Mysql 函数大全
  12. 2018.08.21随笔
  13. NYOJ 93 汉诺塔(三) 【栈的简单应用】
  14. Windows 安装两个MYSQL实例
  15. QQ for linux不用udp8000端口?
  16. python程序员专用壁纸_程序员如何一键“Get”高清壁纸?
  17. Python爬虫编程思想(133):项目实战--利用Appium抓取微信朋友圈信息
  18. 天津教育杂志天津教育杂志社天津教育编辑部2022年第30期目录
  19. 4S店维修陷阱 零配件以换代修成潜规则
  20. linux里怎么看终端类型,如何区分Linux下的几种终端类型:tty、pty和pts

热门文章

  1. 开源正弦波20kHz信号发生器电路分析
  2. 【angular5】浅谈angular5与serviceWorker——(2)
  3. 【Oracle数据库驱动架包 ojdbc5.jar ojdbc6.jar】
  4. 程序变量命名法:匈牙利命名、驼峰式、帕斯卡命名法
  5. 4G图传移动视频取证-可视安全生产监管-常见问题解答FAQ-1,C/S客户端软件常用操作
  6. python endswith函数_python endswith和startwith
  7. 大量的Oracle数据库视频教程提供下载
  8. 微信小程序——弹出并隐藏键盘(带有输入框,可编辑)
  9. 虚拟机VMware使用U盘装系统
  10. ES6代码转换为ES5的代码