給定一棵樹,邊的顏色為黑或白,初始時全部為白色。維護兩個操作:
1.查詢u到根路徑上的第一條黑色邊的標號。
2.將u到v 路徑上的所有邊的顏色設為黑色。
notice:這棵樹的根節點為1
第一行兩個數n,m分別表示點數和運算元。
接下來n-? 1行,每行2個數u,v.表示一條u到v的邊。
接下來m行,每行為以下格式:
1 v 表示第乙個操作
2 v u 表示第二種操作
對於每個詢問,輸出相應答案。如果不存在,輸出0。
5 41 2
1 32 4
2 51 2
2 2 3
1 31 402
1對於 100% 的資料:n,m<=10^6
題解:本題要用到兩邊並查集。
先用並查集預處理出每條邊第一次變黑的時間,然後時間倒流。如果這個點是白點,則將該點的並查集與其父親的並查集合並;如果是黑點則不合併。這樣,每個點所在的並查集的根節點的邊就是路徑上第乙個黑邊。
#include #include #include using namespace std;const int maxn=1000010;
int n,m,cnt;
int to[maxn<<1],next[maxn<<1],head[maxn],vis[maxn],f[maxn],v[maxn];
int dep[maxn],fa[maxn],son[maxn],top[maxn],siz[maxn],q[maxn],ans[maxn];
inline int rd()
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}void add(int a,int b)
void dfs1(int x)
}void dfs2(int x,int tp)
int lca(int x,int y)
} for(i=1;i<=n;i++) f[i]=!vis[i]?fa[i]:i;
for(i=m;i>=1;i--)
for(i=1;i<=m;i++) if(q[i]) printf("%d\n",ans[i]);
return 0;
}
BZOJ3712 Fiolki(並查集重構樹)
bzoj 很神仙的題目。我們發現所有的合併關係構成了一棵樹。那麼兩種不同的東西如果產生反應,一定在兩個聯通塊恰好聯通的時候反應。那麼,我們按照並查集的合併順序,類似於克魯斯卡爾重構樹的方法構建乙個並查集重構樹,發現所有的反應恰好在兩者的 lca 處發生,所以把所有可以發生的翻譯拿出來,按照 lca ...
偶數樹 並查集
給你一棵有n個節點的樹 乙個無環簡單圖 節點序號為1 n,根節點為1。請你找出乙個最大的整數k,表示從這棵樹上斷掉k條邊使其所有的子樹的節點數都為偶數。第一行輸入兩個整數n,m。表示這棵樹有n個節點和m條邊。接下來有m行,每行輸入兩個整數u,v,表示u節點和v節點間有一條邊相連。資料保證 2 n 1...
BZOJ5005 桌球遊戲 線段樹 並查集
如果乙個區間的端點在區間內,則這個區間可以走到那個區間,詢問乙個區間能否到另乙個區間。首先我們立馬想到了 如果兩個區間嚴格有交集,那麼這兩個區間所能到達的區間集合是一樣的。那麼如果兩個區間嚴格有交集的話我們就可以把它們合併起來,這裡運用並查集。這樣處理完之後,剩下的區間只有兩種情況 包含或者相離。那...