生活随笔
收集整理的這篇文章主要介紹了
CF1528C dfs序+set维护
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
給你兩棵有nnn個節點的樹,我門記第一棵為aaa,第二棵為bbb,現在你有一個nnn個點都孤立的點集,兩個點u,vu,vu,v可以連邊當且僅當這兩個點在aaa樹中一個是另一個的祖先節點且在bbb樹中每個都不是另一個的祖先節點,讓你求連完邊之后的最大聯通塊的大小是多少。
兩棵樹都以111為根。
n≤3e5n\le 3e5n≤3e5
思路:
首先我們知道答案選的點一定是aaa樹中從根節點到葉子節點的路徑上點的一個子集,這啟發我們可以從aaa樹的根開始向下dfsdfsdfs,維護走過的點,現在我們的問題就是如何從我們維護的點中選出一個最大的點集使其在bbb樹中都是符合條件的。
在bbb樹中選出來的每兩個點都不互為祖先,那么他們倆一定在一棵子樹內,涉及子樹問題我們可以將其轉換成dfsdfsdfs序。
首先需要了解dfsdfsdfs序的性質,dfsdfsdfs序將每個子樹劃分為了若干區間,也就是每個子樹的根有一個區間[l,r][l,r][l,r],且劃分的若干區間只會有兩種情況:一個區間完全包含另一個區間,兩個區間完全不相交。
現在我們對bbb樹求一個dfsdfsdfs序,現在每個點都轉換成一個區間了,對aaa來說我們只需要需要維護一個從根到當前點的若干個不相交線段,可以分以下兩個情況:
(1)(1)(1)如果我們當前插入的點uuu的區間[lu,ru][l_u,r_u][lu?,ru?]包含了之前插入的區間,那么我們肯定是舍棄這個點是更優的。
(2)(2)(2)如果我們當前插入的點在前面已經有的點的區間內的話,那么肯定是將前面大區間刪掉,加入當前區間是更優的。
以上操作可以用setsetset維護一下in[u]in[u]in[u],讓后lowerboundlower_boundlowerb?ound找離他最近的點的in[v]in[v]in[v],判斷一下就好啦,第二種情況同理,只需要讓it??it--it??即可,具體的看代碼比較好懂。
復雜度O(nlogn)O(nlogn)O(nlogn)。
Update:Update:Update:
由于題目保證了ai<ia_i<iai?<i,那么說明標號一定是遞增的,所以不會出現當前區間是大區間,之前有小區間的情況,所以it==s.end()∣∣?it>out[u]it==s.end()||*it>out[u]it==s.end()∣∣?it>out[u]這個判斷條件可以直接去掉。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
int in
[N
],out
[N
],id
[N
],tot
,ans
;
set
<int>s
;
vector
<int>v1
[N
],v2
[N
];void dfs2(int u
) {in
[u
]=++tot
; id
[tot
]=u
;for(auto x
:v2
[u
]) dfs2(x
);out
[u
]=tot
;
}void dfs1(int u
) {int flag
=false;int del
=-1;auto it
=s
.lower_bound(in
[u
]);if(it
==s
.end()||*it
>out
[u
]) {if(it
!=s
.begin()) {it
--;if(out
[id
[*it
]]>=in
[u
]) {del
=*it
;s
.erase(it
);}}s
.insert(in
[u
]);flag
=true;}ans
=max(ans
,(int)s
.size());for(auto x
:v1
[u
]) dfs1(x
);if(flag
) {s
.erase(in
[u
]);if(del
!=-1) s
.insert(del
);}
}int main()
{
int _
; scanf("%d",&_
);while(_
--) {scanf("%d",&n
);tot
=0; s
.clear(); ans
=0;for(int i
=1;i
<=n
;i
++) v1
[i
].clear(),v2
[i
].clear();for(int i
=2;i
<=n
;i
++) {int x
; scanf("%d",&x
);v1
[x
].pb(i
);}for(int i
=2;i
<=n
;i
++) {int x
; scanf("%d",&x
);v2
[x
].pb(i
);}dfs2(1); dfs1(1);printf("%d\n",ans
);}return 0;
}
總結
以上是生活随笔為你收集整理的CF1528C dfs序+set维护的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。