CodeForces - 1529E Trees of Tranquillity(贪心+线段树)
題目鏈接:https://vjudge.net/problem/CodeForces-1529E
題目大意:給出兩棵根節點為 111 的樹,分別稱為 AAA 樹和 BBB 樹,現在通過兩棵樹可以構造出一個無向圖,當且僅當點對 (x,y)(x,y)(x,y) 同時滿足以下兩個條件時,可以在圖中建邊:
求該圖的最大團
題目分析:一開始讀錯題了,后來讀對題后分析的差不多時間也到點了,今天補題的時候發現和賽場的思路差的不算太多,就是一個挺簡單的貪心
思考一下,滿足最大團的點,在 AAA 樹上和 BBB 樹上的形態是什么樣的,首先這些點在 AAA 樹上一定是一條,從根節點到葉子結點的鏈上的點,可以不連續。在 BBB 樹上就可以體現為,所有點的 dfsdfsdfs 序都沒有交集
繼續分析,所有點的 dfsdfsdfs 序沒有交集,也就是說需要選擇盡可能多的區間,使其互不相交,這樣就將樹上的問題轉換成線性問題了
而在 AAA 樹上需要滿足所有的點在同一條鏈上,在 dfsdfsdfs 的時候貪心選擇盡可能多的點就可以了
然后是題目針對于本題輸入的一個特殊性質,基于給出的樹的輸入方式,是每次給出點 iii 的父節點。這也就使得,AAA 樹和 BBB 樹從根節點拉下來的一條鏈,一定是一個單調遞增的序列,結合于此,針對于 BBB 樹的 dfsdfsdfs 序的區間,有一個下面會用到的性質:
序號較小的點的區間,要么包含序號較大的點的區間,要么與其不相交
接下來就可以對 AAA 樹 dfsdfsdfs 去貪心了,需要維護一個數據結構,需要實現以下功能:
可以用平衡樹(set),也可以用線段樹,我覺得用線段樹比較好理解,就選擇了線段樹實現
當遍歷到點 xxx 時,嘗試將點 xxx 所代表的區間插入到線段樹中,無非會出現三種情況:
回溯的時候將 xxx 所代表的區間按照上述三種情況還原即可
最后的最后還有一個比較難解決的小問題,就是,如何快速查詢區間 [L[x],R[x]][L[x],R[x]][L[x],R[x]] 中存在的不同區間的個數,以及如何快速更新線段樹
還記得前面加粗的性質嗎?序號大小這個條件還沒有用上呢
其實我們可以直接去查詢 [L[x],R[x]][L[x],R[x]][L[x],R[x]] 中,存在的區間的最大編號即可,因為在 AAA 樹上 dfsdfsdfs 遍歷的鏈也是遞增遍歷的,結合加粗的性質,如果 [L[x],R[x]][L[x],R[x]][L[x],R[x]] 之前被覆蓋過,那么一定是一個更大的區間覆蓋的,所以上述的三種情況里,第三種情況實際上根本不可能出現
代碼:
// Problem: E. Trees of Tranquillity // Contest: Codeforces - Codeforces Round #722 (Div. 2) // URL: https://codeforces.com/contest/1529/problem/E // Memory Limit: 256 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; vector<int>a[N],b[N]; int L[N],R[N],dfn,sum,ans; struct Node {int l,r,mmax,lazy; }tree[N<<2]; void pushup(int k) {tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax); } void pushdown(int k) {if(tree[k].lazy!=-1) {int lz=tree[k].lazy;tree[k].lazy=-1;tree[k<<1].mmax=tree[k<<1|1].mmax=lz;tree[k<<1].lazy=tree[k<<1|1].lazy=lz;} } void build(int k,int l,int r) {tree[k]={l,r,0,-1};if(l==r) {return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); } void update(int k,int l,int r,int val) {if(tree[k].l>r||tree[k].r<l) {return;}if(tree[k].l>=l&&tree[k].r<=r) {tree[k].mmax=tree[k].lazy=val;return;}pushdown(k);update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k); } int query(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l) {return 0;}if(tree[k].l>=l&&tree[k].r<=r) {return tree[k].mmax;}pushdown(k);return max(query(k<<1,l,r),query(k<<1|1,l,r)); } void dfs1(int u) {L[u]=++dfn;for(auto v:b[u]) {dfs1(v);}R[u]=dfn; } void dfs2(int u) {int mmax=query(1,L[u],R[u]);if(!mmax) {update(1,L[u],R[u],u);sum++;} else {update(1,L[mmax],R[mmax],0);update(1,L[u],R[u],u);}ans=max(ans,sum);for(auto v:a[u]) {dfs2(v);}if(!mmax) {update(1,L[u],R[u],0);sum--;} else {update(1,L[u],R[u],0);update(1,L[mmax],R[mmax],mmax);} } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;while(w--) {int n;read(n);dfn=0;for(int i=1;i<=n;i++) {a[i].clear();b[i].clear();}for(int i=2;i<=n;i++) {int fa;read(fa);a[fa].push_back(i);}for(int i=2;i<=n;i++) {int fa;read(fa);b[fa].push_back(i);}dfn=ans=sum=0;build(1,1,n);dfs1(1);dfs2(1);cout<<ans<<endl;}return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 1529E Trees of Tranquillity(贪心+线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1484E S
- 下一篇: CodeForces - 1529F I