[LOJ#2129][NOI2015]程序自動分析
阿新 • • 發佈:2019-04-06
圖片 。。 spa end sig bool bre 時間 gis
練習並查集必做系列。
題目給定的操作有\(2\)種:相等或不相等。
這裏沒有要求實時查詢,所以(對於每組數據)打亂查詢順序也無可厚非。
一次我們不妨先處理\(e=1\)的情況,將信息存入並查集中。
再取\(e=0\)的情況,如果\(find(x)==find(y)\),那麽該邏輯不合法。
如果從頭到腳都是合法的,就是判定為可以被滿足的。
代碼:
#include<cstdio> using namespace std; const int N=1e7+10; const int M=1e5+10; int uset[N]; int find(int x){ return (uset[x]==x)?x:uset[x]=find(uset[x]); } inline void merge(int x,int y){ uset[find(y)]=find(x); } int x[M],y[M],e[M]; int m,T; int main() { scanf("%d",&T); while(T--) { register int i; bool flag=1; scanf("%d",&m); for(i=1;i<=m;i++)scanf("%d%d%d",&x[i],&y[i],&e[i]); for(i=1;i<=N;i++)uset[i]=i; for(i=1;i<=m;i++) { if(!e[i])continue; merge(x[i],y[i]); } for(i=1;i<=m&&flag;i++) { if(e[i])continue; if(find(x[i])==find(y[i]))flag=0; } if(flag)puts("YES"); else puts("NO"); } return 0; }
\(\text{But----}\)
什麽玩意兒?!
我們再瞄一眼數據規模:
難道開1e9的數組。。。
我們也許會使用map
這種神奇的STL,這是一種極為省力的方法。
map
版Code(不解釋了。):
#include<cstdio> #include<map> using namespace std; const int MAX_N=1e5+1; map<int,int>num; int n; int x[MAX_N],y[MAX_N]; int b[MAX_N]; int fa[MAX_N*2]; int find(int x){return (fa[x]==x)?x:fa[x]=find(fa[x]);} inline void merge(int x,int y){fa[find(x)]=find(y);} int main() { int T; scanf("%d",&T); while(T--) { register int i; bool flag=0; int cnt=0; scanf("%d",&n); num.clear(); for(i=1;i<=n;i++) { scanf("%d%d%d",&x[i],&y[i],&b[i]); if(num.find(x[i])==num.end())num[x[i]]=++cnt; if(num.find(y[i])==num.end())num[y[i]]=++cnt; } for(i=1;i<=cnt;i++)fa[i]=i; for(i=1;i<=n;i++) { if(!b[i])continue; merge(num[x[i]],num[y[i]]); } for(i=1;i<=n;i++) { if(b[i])continue; if(find(num[x[i]])==find(num[y[i]])) { flag=1; break; } } if(flag)puts("NO"); else puts("YES"); } }
\(Result->\)
效果不差!但是這樣的時間並不是最高效的,而且如果在Luogu上評測,還極有可能T掉一個點。
考慮到map
的(1次)加入和查找操作的時間復雜度\(O(\log_2 n)\),這將造成大量的時間消耗!
所以這裏有一個一次性搞定的方法。
輸入時,將\(x_i,x_j\)中的\(i,j\)存入數組
nums
中(此處nums
要開到2e5
的大小)。然後將
nums
數組排序,然後去重(在#include<algorithm>
庫中有sort
函數(排序)和unique
函數(去重))。接下來將輸入的數據_映射成這個數據在_
nums
中的下標(聽說lower_bound
此時此刻,初始數據已經成為了大小在\([1,2\times 10^5]\)中的整數!
然後開2e5的並查集,進行上述的算法。
\[\text{MainCodeHere}\]
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=1e5+10;
int uset[MAX_N*2];
int x[MAX_N],y[MAX_N],e[MAX_N];
int nums[MAX_N*2];
int n,total;
int find(int x){
return (x==uset[x])?x:uset[x]=find(uset[x]);
}
inline void merge(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy)return;
uset[fx]=fy;return;
}
signed main()
{
int T;scanf("%d",&T);
while(T--)
{
register int i;
total=-1;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&x[i],&y[i],&e[i]);
nums[++total]=x[i];
nums[++total]=y[i];
}
sort(nums,nums+total);
int tmp=unique(nums,nums+total)-nums;
total=tmp;
for(i=1;i<=n;i++)
{
x[i]=lower_bound(nums,nums+total,x[i])-nums;
y[i]=lower_bound(nums,nums+total,y[i])-nums;
}
for(i=0;i<=total;i++)uset[i]=i;
for(i=1;i<=n;i++)
if(e[i])
merge(x[i],y[i]);
bool flag=1;
for(i=1;i<=n&&flag;i++)
if(!e[i]&&find(x[i])==find(y[i]))
flag=0;
if(flag)puts("YES");
else puts("NO");
}
return 0;
}
perfect!
[LOJ#2129][NOI2015]程序自動分析