1. 程式人生 > 其它 >2021牛客暑期多校訓練營7

2021牛客暑期多校訓練營7

F xay loves trees

還是第一次做到這種兩棵樹(兩個圖)的題目,自然是不可能在兩棵樹上同時搞得,因為兩棵樹結構都不同....

題目要求選的點在第一棵樹上必須是連續的鏈狀,在第二棵樹上任何兩個點都不能是祖宗,祖先的關係,換句話說在第二棵樹上,任何一個點都不能是另一個點的子樹中的點。

既然第一棵樹上的要求比較嚴苛,我們可以考慮在第一棵樹上進行操作,將第二棵樹上的要求當做第一棵樹上的限制條件。

因為在第一棵樹上必須是鏈,這很符合我們的dfs的要求,我們將樹上的鏈轉化成序列上的問題思考怎麼解決,對於這種區間最長的問題,我們很容易想到尺取法,我們可以找一下每個右端點最小的左端點,發現當右指標遞增時,左指標也一定遞增。譬如當右指標為r時,左指標為l,則當右指標為r+1時,左指標左邊的一定不用再考慮了,因為r已經在區間內了,而r和l左邊的有衝突,所以左指標也一定遞增。這就保證了我們的複雜度是O(n)的。我們把它放到樹上,也就是說在dfs的時候維護一個左右指標就行,那怎麼判斷當前的序列合不合法?由於在第二棵樹上,任何一個點都不能是另一個點的子樹中的點,所以我們可以每次選擇一個節點後都將這個節點及其字數都染色,之後判斷一個點是否可進入我們的序列中時,我們只需要判斷它的子樹中是否有值即可。若有值則之前選的點中一定有它的祖先或兒子。這用dfs序加線段樹就行。

//不等,不問,不猶豫,不回頭.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define
putl(x) printf("%lld\n",x) #define rep(x,y,z) for(int x=y;x<=z;++x) #define fep(x,y,z) for(int x=y;x>=z;--x) #define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y) using namespace std; const int N=3e5+10; int dfn[N],Size[N],num,b[N],ans,n; vector<int>v1[N],v2[N]; struct Tree {
int l,r,tag,dat; #define l(x) t[x].l #define r(x) t[x].r #define tag(x) t[x].tag #define dat(x) t[x].dat }t[N<<2]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void init() { get(n); rep(i,1,n) v1[i].clear(),v2[i].clear(); rep(i,1,n-1) { int get(x),get(y); v1[x].push_back(y); v1[y].push_back(x); } rep(i,1,n-1) { int get(x),get(y); v2[x].push_back(y); v2[y].push_back(x); } } inline void dfs(int x,int father) { dfn[x]=++num;Size[x]=1; for(auto y:v2[x]) { if(y==father) continue; dfs(y,x); Size[x]+=Size[y]; } } inline void build(int p,int l,int r) { l(p)=l;r(p)=r; if(l==r) {dat(p)=tag(p)=0;return;} int mid=l+r>>1; build(ls,l,mid); build(rs,mid+1,r); dat(p)=tag(p)=0; } inline void push(int p) { if(tag(p)) { dat(ls)+=tag(p); dat(rs)+=tag(p); tag(ls)+=tag(p); tag(rs)+=tag(p); tag(p)=0; } } inline int ask(int p,int l,int r) { if(l<=l(p)&&r>=r(p)) return dat(p); push(p); int mid=l(p)+r(p)>>1; int ans=-INF; if(l<=mid) ans=max(ans,ask(ls,l,r)); if(r>mid) ans=max(ans,ask(rs,l,r)); return ans; } inline void alter(int p,int l,int r,int k) { if(l<=l(p)&&r>=r(p)) { dat(p)+=k; tag(p)+=k; return; } push(p); int mid=l(p)+r(p)>>1; if(l<=mid) alter(ls,l,r,k); if(r>mid) alter(rs,l,r,k); dat(p)=max(dat(ls),dat(rs)); } inline void dfs(int x,int father,int l,int r) { ans=max(ans,r-l+1); for(auto y:v1[x]) { if(y==father) continue; int L=l,R=r;//記錄加入y之後的指標. while(ask(1,dfn[y],dfn[y]+Size[y]-1)) { alter(1,dfn[b[L]],dfn[b[L]]+Size[b[L]]-1,-1); L++; } alter(1,dfn[y],dfn[y]+Size[y]-1,1); b[++R]=y; dfs(y,x,L,R); rep(i,l,L-1) alter(1,dfn[b[i]],dfn[b[i]]+Size[b[i]]-1,1); alter(1,dfn[y],dfn[y]+Size[y]-1,-1); } } int main() { //freopen("1.in","r",stdin); int get(T); while(T--) { init(); num=0;dfs(1,0); build(1,1,n); ans=0;b[1]=1; alter(1,dfn[1],dfn[1]+Size[1]-1,1); dfs(1,0,1,1); put(ans); } return (0^_^0); } //以吾之血,鑄吾最後的亡魂.
View Code