1. 程式人生 > 實用技巧 >scala入門[Hello,world]

scala入門[Hello,world]

IInteresting Computer Game

並查集+樹狀陣列離散化

要點一、由於題目中給出的對於a陣列的資料範圍在1~1e9,直接利用陣列是不現實的,所以我們用陣列a下標開陣列,這個範圍是1~1e5,開陣列是能夠接受的。

要點二、之前讀取的資料存在重複,則需要對其進行去重操作。

要點三、查詢連通塊,如果是,輸出連通塊中的節點個數;否則節點數減一。

#include <bits/stdc++.h>
#define T int t ;cin >> t;while(t--)
using namespace std ;
typedef long long ll;
const
int maxn = 2e5 + 10; ll vis[maxn],a[maxn],b[maxn],c[maxn],pre[maxn]; //vis陣列表示的是當前的節點是否被訪問過 //pre陣列表示的是合併路徑 inline ll find(ll x) { return (x==pre[x]) ? x:pre[x]=find(pre[x]); } inline void merge(ll u,ll v) { ll x=find(u),y=find(v); if(x==y) { vis[x]=1; return; } pre[x]
=y;//表示x,y的祖宗合併,即兩者為同一祖先 if(vis[x])vis[y]=1;//該節點表示已被訪問 } int main() { ll total=0;//用於輸出Case情況的個數 T { total++; ll n; ll tot=0;//tot表示存入數的個數 scanf("%lld",&n); for(ll i=1; i<=n; i++) { scanf("%lld%lld",&a[i],&b[i]); c[
++tot]=a[i];//c陣列用於存放每個數字,方便接下去排序和去重 c[++tot]=b[i]; } for(ll i=0; i<=maxn; i++)//初始化操作 { vis[i]=0; pre[i]=i; } sort(c+1,c+tot+1);//升序排序,便於接下來的去重 int cnt=unique(c+1,c+tot+1)-(c+1);//去重,方便編號 for(ll i=1; i<=n; i++) { a[i]=lower_bound(c+1,c+tot+1,a[i])-c; //從陣列的begin位置到end-1位置二分查詢第一個大於或等於num的數字, //找到返回該數字的地址,不存在則返回end。 //通過返回的地址減去起始地址begin,得到找到數字在陣列中的下標,下標即樹的度數 b[i]=lower_bound(c+1,c+tot+1,b[i])-c; merge(a[i],b[i]);//用下標代替實際數字,防止陣列存不下 } int ans=tot; for(ll i=1; i<=tot; i++) { if(pre[i]==i&&!vis[i])ans--;//根據《離散數學》相關知識,如果非連通塊則ans減一 } cout<<"Case #"<<total<<": "<<ans<<endl; } }

KKabaleo Lite