数据结构
队列
队首只能删除,访问
队尾只能插入
满足先进先出的原则
三种主要操作
在队尾加入一个元素 push O(1)
弹出队首元素 pop O(1)
获得队首元素的值 front O(1)
可以使用数组模拟或使用 stl 中的 queue
队列的实现
队列的结构体实现
#include<iostraem>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
const int n=10000;
struct Queue{
int q[n];
int l,r;
void intl(){
l=1;
r=0;
}
void push(int x){
++r;
if(r=n)
r=1;
q[r]=x;
}
int front(){
return q[l];
}
void pop(){
l++;
}
int size(){
if(l<r){
return r-l+1;
}
else return n-l+r-1;
}
};
STL中的队列
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int main(){
queue<int>q;
q.push(1);
if(q.empty()==0){
cout<<q.front()<<endl;
cout<<q.back()<<endl;
cout<<q.size()<<endl;
}
q.pop();
return 0;
}
队列的应用
BFS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<queue>
using namespace std;
const int x=100005;
int main(){
int n,m;
cin>>n>>m;
int u,v;
for(int i=1;i<=m;i++){
cin>>u>>v;
f[u][0]++;
f[u][f[u][0]]=v;
}
bool v[x]=ture;
for(int i=1;i<=n;i++){
v[i]=false;
}
queue<int>q;
q.push(1);
int now;
while(q.size()){
now=q.front();
q.pop();
for(int i=1;i<=sizeof(f[now]);i++){
if(!f[now][i]){
v[f[now][i]]=true;
q.push(f[now][i]);
}
}
}
}
单调队列
(洛谷 P1886 滑动窗口)
-static用于定义静态变量-
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
struct que{
static const int maxn=1000005;
int n,k,q[maxn],a[maxn],p[maxn];
int head,tail;
void read(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
}
void minn(){
head=1;
tail=0;
for(int i=1;i<=n;i++){
while(q[tail]>=a[i]&&head<=tail){
tail--;
}
q[++tail]=a[i];
p[tail]=i;
while(p[head]<=i-k){
head++;
}
if(i>=k){
printf("%d ",q[head]);
}
}
printf("\n");
}
void mxnn(){
head=1;
tail=0;
for(int i=1;i<=n;i++){
while(tail>=head&&q[tail]<=a[i]){
tail--;
}
q[++tail]=a[i];
p[tail]=i;
while(p[head]<=i-k){
head++;
}
if(i>=k){
printf("%d ",q[head]);
}
}
printf("\n");
}
}hh;
int main(){
hh.read();
hh.minn();
hh.mxnn();
return 0;
}
栈
实现
结构体
struct Stack{
int a[1000005];
int top;
void inti(){ top=0;}
void push(int x){a[++top]=x;}
void pop() {if(top) top--;}
int size() {return top;}
int quary(){return a[top];}
};
stl
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 在栈顶增加元素
size() 返回栈中元素数目
top() 返回栈顶元素
应用
递归
深度优先搜索
例题
初始时从左到右有 n 个木块,编号为 0 n-1, 要求实现下列四种
操作:
move a onto b: 把 a 和 b 上方的木块全部放回初始的位置,然后
把 a 放到 b 上面
move a over b: 把 a 上方的木块全部放回初始的位置,然后把 a
放在 b 所在木块堆的最上方
pile a onto b: 把 b 上方的木块部放回初始的位置,然后把 a 和 a
上面所有的木块整体放到 b 上面
pile a over b: 把 a 和 a 上面所有的木块整体放在 b 所在木块堆
的最上方
一个字符串表示逻辑式子,其中包含 true, false, or, and, not
和空格优先级为 not, and, or。同级左边先算,如果逻辑式有误则
输出 error。
链表
实现
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct Node{
int data;
NOde *next;
};
Node *head,*p,*r;
int x;
int main(){
cin>>x;
head=new Node;
r=head;
while(x!=-1){
p=new Node;
p->data=x;
p->next=NULL;
r->next=p;
r=p;
cin>>x;
}
p=head->next;
while(p->next!=NULL){
cout<<p->data<<" ";
p=p->next;
}
cout<<p->data<<endl;
return 0;
}
操作
插入
void insert(Node *head,int i,int x){
Node *p,*s;
int j;
p=head;
j=0;
while((p!=NULL)&&(j<i-1)){
p=p->next;
j=j+1;
}
if(p==NULL){
cout<<"no this position"<<endl;
}
else {
s=new Node;
s->data=x;
s->next=p->next;
p->next=s;
}
}
插入
void delet(Node *head,int i){
Node *p,*s;
int j;
p=head;
j=0;
while((p->next!=NULL)&&(j<i-1)){
p=p->next;
j=j+1;
}
if(p->next==NULL){
cout<<"no this position"<<endl;
}
else{
s=p->next;
p->next=s->next;
free(s);
}
}
长度
int len(Node *head){
int cnt=0;
Node *p;
while(p->data!=NULL){
cnt++;
p=p->next;
}
return n;
}
并查集
洛谷P3367
#in#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
int n,m,x,y,z;
int f[N];
int siz[N];
void swap(int &a,int &b){
int t=a;
a=b;
b=t;
}
int find(int a){
if(f[a]==a) return a;
else return f[a]=find(f[a]);//路径压缩
}
void merge(int x,int y){
int xx=find(x),yy=find(y);
if(siz[xx]>siz[yy]) swap(xx,yy);//按秩合并
f[xx]=yy;
siz[yy]=siz[yy]+siz[xx];//按秩合并
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
f[i]=i;
siz[i]=1;
}
for(int i=1;i<=m;i++){
cin>>z;
if(z==1){
cin>>x>>y;
merge(x,y);
}
if(z==2){
cin>>x>>y;
if(find(x)==find(y)) puts("Y");
else puts("N");
}
}
return 0;
}
}
二叉堆
https://www.cnblogs.com/henry-1202/p/9307927.html
小根堆
洛谷 P3378【模板】堆
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int siz,n;
int heap[30001];
void swap(int &a,int &b){
int c=a;
a=b;
b=c;
}
void put(int x){
int now,nxt;
heap[++siz]=x;
now=siz;
while(now>1){
nxt=now>>1;
if(heap[now]>=heap[nxt]) return ;
swap(heap[now],heap[nxt]);
now=nxt;
}
}
void get(){
int now,nxt;
heap[1]=heap[siz--];
now=1;
while(now*2<=siz){
nxt=now<<1;
if(nxt+1<=siz&&heap[nxt+1]<heap[nxt]) nxt++;
if(heap[now]<heap[nxt]) return ;
swap(heap[now],heap[nxt]);
now=nxt;
}
return ;
}
int main(){
cin>>n;
int x,y;
for(int i=1;i<=n;i++){
cin>>x;
if(x==1){
cin>>y;
put(y);
}
if(x==2){
cout<<heap[1]<<endl;
}
if(x==3)
get();
}
return 0;
}
大根堆
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int siz;
int heap[100005];
void swap(int &x,int &y){
int z=x;
x=y;
y=z;
}
void push(int x){
int now,nxt;
heap[++siz]=x;
now=siz;
while(now>1){
nxt=now<<1;
if(heap[nxt]>=heap[now]) break;
swap(heap[now],heap[nxt]);
now=nxt;
}
return ;
}
void pop(){
int now,nxt;
heap[1]=heap[siz--];
now=siz;
while(now*2<=siz){
nxt=now<<1;
if(nxt+1<=siz&&heap[nxt]<heap[nxt+1]) nxt++;
if(heap[now]>=heap[nxt]) break;
swap(heap[now],heap[nxt]);
now=nxt;
}
return;
}
stl版堆
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int siz;
int heap[1000005];
void push(int x){
heap[++siz]=x;
push_heap(heap+1,heap+1+siz,greater<int>());
}
void pop(){
pop_heap(heap+1,heap+1+siz,greater<int>());
siz--;
}
int main(){
int n;
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==1){
scanf("%d",&x);
push(x);
}
if(x==2){
printf("%d\n",heap[1]);
}
if(x==3){
pop();
}
}
return 0;
}
优先对列实现堆
#include<bits/stdc++.h>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;//小根堆
//priority_queue<int>q;大根堆
int n,a,b;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
if(a==1){
cin>>b;
q.push(b); // 插入元素
}
if(a==2) cout<<q.top()<<endl;//返回堆顶元素
if(a==3) q.pop() ;//删除堆顶元素
}
return 0;
}
练习
codevs 2977 二叉堆练习1 http://codevs.cn/problem/2977/
#include<bits/stdc++.h>
using namespace std;
int n,f[200020];
bool pd=1;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&f[i]);
}
for(int i=1;i<=n;i++)
{
if(f[i]<f[i*2]&&f[i*2]>0){
if(f[i*2+1]>0&&f[i*2+1]<f[i]){
pd=0;
}
}
if(f[i]>f[i*2]&&f[i*2]>0){
pd=0;
}
}
if(pd) printf("YES");
else printf("NO");
return 0;
}
codevs 3110 二叉堆练习3 http://codevs.cn/problem/3110/
#include<bits/stdc++.h>
#include<queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int n,m;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&m);
q.push(m);
}
for(int i=1;i<=n;i++){
printf("%d ",q.top());
q.pop();
}
return 0;
}
线段树
http://www.cnblogs.com/TheRoadToTheGold/p/6254255.html
普通版
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct{
int l,r,w;
}tree[1000];//需开四倍大小的数组
//建树,即建立一棵线段树
void build(int l,int r,int k){
tree[k].l=l;
tree[k].r=r;
if(l==r){
scanf("%d",&tree[k].w);
return ;
}
int m=(l+r)/2;
build(l,mid,k*2);
build(mid+1,r,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
//单点查询,即查询一个点的状态,设待查询点为x
int ans;
int x;//x为目标节点
void ask(int k){
if(tree[k].l==tree[k].r){
ans=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) ask(k*2);
else ask(k*2+1);
}
//单点修改,即更改某一个点的状态。用引例中的例子,对第x个数加上y
int y//y为待加值
void add(int k){
if(tree[k].l==tree[k].r){
tree[k].w+=y;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) add(k*2);
else add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
//区间查询,即查询一段区间的状态,在引例中为查询区间[x,y]的和
int ans1;
int a,b;//[a,b]为待查询区间
void sum(int k){
if(tree[k].l>=a&&tree[k].r<=b){
ans1+=tree[k].w;
return ;
}
int m=(tree[k].l+tree[k].r)/2;
if(x>=m) sum(k*2);
if(y<=m) sum(k*2+1);
}
int main(){
}
懒标记版
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct{
int l,r,w,f;
}tree[1000];
void down(int k){
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k].f=0;
}
void build(int l,int r,int k){
tree[k].l=l;
tree[k].r=r;
if(l==r){
scanf("%d",&tree[k].w);
return ;
}
int m=(tree[k].l+tree[k].r)/2;
build(l,m,k*2);
build(m+1,r,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int x;
int ans;
void ask(int k){
if(tree[k].l==tree[k].r){
ans=tree[k].w;
return ;
}
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) ask(k*2);
else ask(K*2+1);
}
int x,y;
void add(int k){
if(tree[k].l==tree[k].r){
tree[k].w+=y;
return ;
}
if(tree[k].f) down(k);//???
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) add(k*2);
else add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int a,b;
ans=0;
void sum(k){
if(tree[k].l>=a&&tree[k].r<=b){
ans+=tree[k].w;
return ;
}
if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(a<=m) sum(k*2);
if(b>m) sum(K*2+1);
}
void change(int k){
if(tree[k].l>=a&&tree[k].r<=b){
tree[k].w+=y*(tree[k].r-tree[k].l+1);
tree[k].f+=y;
return ;
}
if(tree[k].f) down(k);//???
int m=(tree[k].l+tree[k].r)/2;
if(a<=m) change(k*2);
if(b>m) change(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
空间优化
父节点k,左二子2k,右儿子2k+1,需要4*n的空间
但并不是所有的叶子节点占用到2n+1——4n
这就造成大量空间浪费
2*n空间表示法:推荐博客:http://www.cppblog.com/MatoNo1/archive/2015/05/05/195857.html
用dfs序表示做节点下标
父节点k,左儿子k+1,右儿子:k+左儿子区间长度*2,不是父节点下标+父节点区间长度。因为当树不满时,两者不相等
但它会减慢运算速度
模版题
1、codevs 1080 线段树练习 (单点修改+区间查询) http://codevs.cn/problem/1080/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,t,q,l;
struct{
int l,r,w;
}tree[400005];
void build(int l,int r,int k){
tree[k].l=l;
tree[k].r=r;
if(l==r){
scanf("%d",&tree[k].w);
return ;
}
int m=(tree[k].l+tree[k].r)/2;
build(l,m,k*2);
build(m+1,r,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int x,y;
void add(int k){
if(tree[k].l==tree[k].r){
tree[k].w+=y;
return ;
}
//if(tree[k].f) down(k);//???
int m=(tree[k].l+tree[k].r)/2;
if(x<=m) add(k*2);
else add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int ans;
int a,b;
void sum(int k){
if(tree[k].l>=a&&tree[k].r<=b){
ans+=tree[k].w;
return ;
}
//if(tree[k].f) down(k);
int m=(tree[k].l+tree[k].r)/2;
if(a<=m) sum(k*2);
if(b>m) sum(k*2+1);
}
int main(){
scanf("%d",&n);
build(1,n,1);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&t,&q,&l);
if(t==1){
x=q;
y=l;
add(1);
}
else{
a=q;
b=l;
sum(1);
printf("%d\n",ans);
ans=0;
}
}
return 0;
}
2、codevs 1081 线段树练习2 (单点查询+区间修改) http://codevs.cn/problem/1081/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct{
int l,r,w,f;
}tree[400005];//开四倍n大小
void down(int k){
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k].f=0;
}
inline void build(int l,int r,int k){
tree[k].l=l;
tree[k].r=r;
if(l==r){
scanf("%d",&tree[k].w);
return;
}
int m=(tree[k].l+tree[k].r)/2;
build(l,m,k*2);
build(m+1,r,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int a,b,x;
inline void add(int k){
if(tree[k].l>=a&&tree[k].r<=b){
tree[k].w+=x*(tree[k].r-tree[k].l+1);
tree[k].f+=x;
return ;
}
if(tree[k].f) down(k);
int m=(tree[k].r+tree[k].l)/2;
if(a<=m) add(k*2);
if(b>m) add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int y;
inline int ask(int k){
if(tree[k].l==tree[k].r) return tree[k].w;
if(tree[k].f) down(k);
int m=(tree[k].r+tree[k].l)/2;
if(y<=m) ask(k*2);
else ask(k*2+1);
}
int n,Q,hh;
int main(){
scanf("%d",&n);
build(1,n,1);
cin>>Q;
for(int i=1;i<=Q;i++){
cin>>hh;
if(hh==1){
scanf("%d%d%d",&a,&b,&x);
add(1);
}
else{
scanf("%d",&y);
cout<<ask(1)<<endl;
}
}
return 0;
}
3、codevs 1082 线段树练习3 (区间修改+区间查询)http://codevs.cn/problem/1082/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct{
ll l,r,w,f;
}tree[800005];//开四倍n大小
inline void down(ll k){
tree[k*2].f+=tree[k].f;
tree[k*2+1].f+=tree[k].f;
tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
tree[k].f=0;
}
inline void build(ll l,ll r,ll k){
tree[k].l=l;
tree[k].r=r;
if(tree[k].l==tree[k].r){
scanf("%lld",&tree[k].w);
return;
}
ll m=(tree[k].l+tree[k].r)/2;
build(l,m,k*2);
build(m+1,r,k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
ll a,b,x;
inline void add(ll k){
if(tree[k].l>=a&&tree[k].r<=b){
tree[k].w+=x*(tree[k].r-tree[k].l+1);
tree[k].f+=x;
return ;
}
if(tree[k].f) down(k);
ll m=(tree[k].r+tree[k].l)/2;
if(a<=m) add(k*2);
if(b>m) add(k*2+1);
tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
ll ans;
inline void ask(ll k){
if(tree[k].l>=a&&tree[k].r<=b){
ans+=tree[k].w;
return ;
}
if(tree[k].f) down(k);
ll m=(tree[k].l+tree[k].r)/2;
if(a<=m) ask(k*2);
if(b>m) ask(k*2+1);
}
ll n,Q,hh;
int main(){
scanf("%lld",&n);
build(1,n,1);
scanf("%lld",&Q);
for(ll i=1;i<=Q;i++){
scanf("%lld",&hh);
ans=0;
if(hh==1){
scanf("%lld%lld%lld",&a,&b,&x);
add(1);
}
else{
scanf("%lld%lld",&a,&b);
ask(1);
printf("%lld\n",ans);
}
}
return 0;
}
树状数组
https://www.cnblogs.com/hsd-/p/6139376.html