CF1446C Xor Tree
阿新 • • 發佈:2020-11-16
對於每個點\(i\),找到\(j\neq i\)且\(a_j \ xor \ a_i\)最小,連邊\((i,j)\)。
如果連邊之後形成一棵樹,那麼稱\(\{a_i\}\)為合法的。
給出\(\{a_i\}\),求至少刪掉多少個點才合法。
\(n\le 2*10^5\)
\(a_i\)互不相同
這題搞得可真是驚心動魄……搞了三個做法,最後一個終於對了……
幹了1.5h。
假設連有向邊\(i\to j\),那麼建出的圖是個基環樹森林。並且每棵基環樹的環長為\(2\)。
如果合法,那麼必須滿足:只存在一對\((i,j)\),滿足對於各自而言,\(a_i\ xor \ a_j\)都是最小的。
自然這也會是全域性最小異或值。之前有個結論,對於一堆樸素的\(\{a_i\}\)
於是最終如何保留樹才合法呢?建出Trie,發現長這樣:
這樣dfs找一下就好了。
using namespace std; #include <cstdio> #include <cstring> #include <algorithm> #define N 200005 #define INF (1<<30) int n; int a[N]; struct Node{ Node *c[2]; int siz; } d[N*40],*rt; int cnt; void insert(int x,int c=1){ Node *t=rt; for (int i=29;i>=0;--i){ t->siz+=c; if (!t->c[x>>i&1]){ t->c[x>>i&1]=&d[++cnt]; d[cnt]={NULL,NULL}; } t=t->c[x>>i&1]; } t->siz+=c; } int ans; void dfs(Node *t,int s){ if (t->c[0] && t->c[0]->siz==1 && t->c[1] && t->c[1]->siz==1) ans=max(ans,2+s); if (t->c[0]) dfs(t->c[0],s+(t->c[1]?1:0)); if (t->c[1]) dfs(t->c[1],s+(t->c[0]?1:0)); } int main(){ // freopen("in.txt","r",stdin); rt=&d[cnt=1]; scanf("%d",&n); for (int i=1;i<=n;++i){ scanf("%d",&a[i]); insert(a[i]); } ans=2; dfs(rt,0); printf("%d\n",n-ans); return 0; }