题248.离散化-洛谷P1955 [NOI2015] 程序自动分析
一、题目
二、题解
本题很容易可以想到用并查集来处理,将等于的两数做并集,然后输入完后不等于的两数一对对的进行查的操作,看看根是否相同,如果相同则本是相等,现在两数又说不等于所以就是NO。但由于i,j的数据范围为1e9过于巨大了属于是,parent数组表示下标对应的父亲的时候显然没办法用下标直接表示那个数点,而n的范围是1e5(它注又写着106),所以parent其实只要开2e5+2(2e6+2)就可以,这样其实我们只需要将i,j放在一个数组里做离散化处理,用离散化处理后的下标来对应parent里的下标,再去做并查集操作就好了。代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e6+2;
int arr[maxn],cnt;
vector<pair<int,int>> eql,noteql;
int parent[maxn];
int flag;
void init()
{
flag=1;
cnt=0;
eql.clear(),noteql.clear();
fill(parent,parent+maxn,-1);
}
int findRoot(int v0)
{
if(parent[v0]<0)
{
return v0;
}
else
{
return parent[v0]=findRoot(parent[v0]);
}
}
void unionSet(int v1,int v2)
{
int root1=findRoot(v1);
int root2=findRoot(v2);
if(root1==root2)
{
return;
}
if(parent[root1]<parent[root2])
{
parent[root1]+=parent[root2];
parent[root2]=root1;
}
else
{
parent[root2]+=parent[root1];
parent[root1]=root2;
}
return;
}
int main()
{
cin.tie(0),cout.tie(0);
int t;
cin>>t;
for(int i=0;i<t;i++)
{
init();
int n;
cin>>n;
for(int j=0;j<n;j++)
{
int a,b,c;
cin>>a>>b>>c;
if(c)
{
eql.push_back({a,b});
arr[cnt++]=a;
arr[cnt++]=b;
}
else
{
noteql.push_back({a,b});
arr[cnt++]=a;
arr[cnt++]=b;
}
}
//数据离散化处理
sort(arr,arr+cnt);
int len=unique(arr,arr+cnt)-arr;
for(int j=0;j<eql.size();j++)
{
int v1=upper_bound(arr,arr+len,eql[j].first)-arr;//找寻数对应的现数组下标
int v2=upper_bound(arr,arr+len,eql[j].second)-arr;
unionSet(v1,v2);
}
for(int j=0;j<noteql.size();j++)
{
int v1=upper_bound(arr,arr+len,noteql[j].first)-arr;
int v2=upper_bound(arr,arr+len,noteql[j].second)-arr;
if(findRoot(v1)==findRoot(v2))
{
flag=0;
break;
}
}
if(flag)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
}
//map做数据离散化
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=2e5+2;
int t,m;
map<int,int> id;//用于做数据离散化
vector<pii> neq;//用于存不等关系,因为得先把等号关系做并查集之后最后再去判断是否矛盾,所以得先存
int p[maxn];
int flag,cnt;
void init()//初始化
{
memset(p,-1,sizeof p);
id.clear();
neq.clear();
flag=cnt=1;
}
int findRoot(int v)
{
if(p[v]<0) return v;
else return p[v]=findRoot(p[v]);
}
void unionSet(int u,int v)
{
int root1=findRoot(u),root2=findRoot(v);
if(root1==root2)
{
return;
}
if(p[root1]<p[root2])
{
p[root1]+=p[root2];
p[root2]=root1;
}
else
{
p[root2]+=p[root1];
p[root1]=root2;
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int u,v,e;
scanf("%d%d%d",&u,&v,&e);
if(!id.count(u)) id[u]=cnt++;
if(!id.count(v)) id[v]=cnt++;
if(e)
{
unionSet(id[u],id[v]);
}
else
{
neq.push_back({id[u],id[v]});
}
}
for(auto e:neq)
{
int u=e.first,v=e.second;
int root1=findRoot(u),root2=findRoot(v);
if(root1==root2)
{
flag=0;
break;
}
}
if(flag)
{
puts("YES");
}
else
{
puts("NO");
}
}
}
三、离散化代码模板
//数据离散化处理
sort(arr,arr+cnt);
int len=unique(arr,arr+cnt)-arr;
upper_bound(arr,arr+len,x)-arr;//找寻x对应的现数组下标
四、关于离散化
1.要求保序
排序,判重,二分(如代码实例)
2.不要求保序
map或者hash表