加工并存储数据的数据结构
重点
- 平衡树(使用unordered_map,multiset,multimap),优先队列(手写堆)
- 并查集
平衡树
用平衡树维护的数,集合,区间,会有一个很好的单调性,可以二分。一般用set维护平衡树(insert,find,erase,count)。用map维护键值对。
//声明int为键,const char*为值
map<int,const char*> m;
//插入元素
m.insert(make_pair(1,"one"));
n.insert(make_pair(10,"ten"));
m [100]="hundred";
//查找元素
map<int,const char*>::iterator it;
it=m.find(1);
puts(it->second);
//没有找到的情况
it=m.find(2);
if(it==m.end) puts("not found");
else puts(it->second);
puts(m[10]);
//删除元素
m.erase(10);
//遍历一遍元素
for(it=m.begin();it!=m.end();++it)
{
cout<<it.first<<" "<<it.second<<endl;
}
unordered_map用于哈希
优先队列
用priority_queue的话不能删除某个任意值,因此一般如果要删除,就需要手写。
#include<iostream>
using namespace std;
const int N=2e5+10;
int h[N],pos[N],pos2[N];
int idx=0;
int size=0;
void down(int x)
{
int t=x;
if(x*2<=size&&h[x*2]<h[t]) t=2*x;
if(x*2+1<=size&&h[x*2+1]<h[t]) t=2*x+1;
if(t!=x)
{
swap(h[t],h[x]);
swap(pos2[t],pos2[x]);
swap(pos[pos2[t]],pos[pos2[x]]);
down(t);
}
}
void up(int x)
{
if(x/2>0&&h[x/2]>h[x])
{
swap(h[x/2],h[x]);
swap(pos2[x/2],pos2[x]);
swap(pos[pos2[x/2]],pos[pos2[x]]);
up(x>>1);
}
}
int main()
{
int n;
cin>>n;
while(n--)
{
string op;
cin>>op;
if(op=="I")
{
int x;
cin>>x;
idx++;
h[++size]=x;
pos[idx]=size;
pos2[size]=idx;
up(size);
}
else if(op=="PM")
{
cout<<h[1]<<endl;
}
else if(op=="DM")
{
swap(h[1],h[size]);
swap(pos2[1],pos2[size]);
swap(pos[pos2[1]],pos[pos2[size]]);
size--;
down(1);
}
else if(op=="D")
{
int k;
cin>>k;
int u=pos[k];
swap(h[u],h[size]);
swap(pos2[u],pos2[size]);
swap(pos[pos2[size]],pos[pos2[u]]);
size--;
up(u);
down(u);
}
else if(op=="C")
{
int k,x;
cin>>k>>x;
h[pos[k]]=x;
up(pos[k]);
down(pos[k]);
}
}
/*cout<<endl;
for(int i=1;i<=size;i++)
{
cout<<h[i]<<" ";
}*/
return 0;
}
并查集
简单的合并集合(模板题)
#include<iostream>
using namespace std;
int p[100010];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
}
int a,b;
string op;
while(m--)
{
cin>>op>>a>>b;
if(op=="M")
{
p[find(b)]=find(a);
}
else
{
if(find(b)==find(a))
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
}
return 0;
}
另外kruskal,图的联通块问题都是以并查集为基础的算法。
食物链
建立三个并查集,把每一个物种归类。
//用x,x+N,x+2*N代表xA,xB,xC
if(t==1)
{
if(same(x,y+N)||same(x,y+N*2))
{
ans++;
}
else
{
unite(x,y);
unite(x+N,y+N);
unite(x+N*2,y+N*2);
}
}
else
{
if(same(x,y)||same(x,y+2*N))
{
ans++;
}
else
{
unite(x,y+N);
unite(x+N,y+2*N);
unite(x+2*N,y);
}
}
等式与不等式
hash+并查集
#include<iostream>
using namespace std;
typedef long long ll;
int p[514748];
int mod=514747;
int a[100001];
int b[100001];
int find(int a)
{
return p[a]==a?a:(p[a]=find(p[a]));
}
void merge(int x,int y)
{
p[find(x)]=find(y);
}
int main()
{
int n,t;
cin>>t;
for(int q=1;q<=t;q++)
{
int flag=1;
int cnt=0;
for(int i=0;i<=514747;i++)
p[i]=i;
cin>>n;
for(int k=1;k<=n;k++)
{
bool e;
ll i,j;
cin>>i>>j>>e;
if(e)
{
merge(i%mod,j%mod);
}
else
{
a[++cnt]=i%mod;
b[cnt]=j%mod;
}
}
for(int j=1;j<=cnt;j++)
{
if(find(a[j])==find(b[j]))
{
flag=0;
cout<<"NO"<<endl;
break;
}
}
if(flag)
cout<<"YES"<<endl;
}
return 0;
}