CF1442E. Black, White and Grey Tree
阿新 • • 發佈:2020-11-07
題目大意
一棵黑白灰的樹,每次選擇一個連通塊內的一個子點集將其刪掉,不能同時刪黑白點,求最少刪完的次數
n<=2e5
題解
不是這DE加起來怎麼還沒有C難寫啊
發現把樹刪成兩個連通塊不比從外往內刪優,因為可以同時刪更多的點
又發現灰色點一定不會先刪,一定是相鄰的點只剩一個時跟著那個點一起刪
轉化一下,先把灰色塊縮成一個點,之後把其相連的黑白點縮成兩個點,最後刪掉灰色點並把合成的黑白兩個點連起來,如果只有某一種顏色就不用連,這樣得到的圖和原圖等價
因為一個灰色點被刪的時間是與其相連的點的最晚被刪時間,所以縮起來之後時間並沒有變
接著再把黑色和白色塊縮起來,變成一棵黑白交替的樹,那麼此時再從葉子一層層往內刪,答案就是直徑/2+1
然後在U群裡看到說直接找直徑就可以了,原理等價於普通樹找直徑,證明用反正法把端點移到直徑端點上
code
#include <bits/stdc++.h> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b; a>=c; a--) #define ll long long //#define file using namespace std; int a[400001][2],b[200001],ls[200001],T,n,i,j,k,l,len,mx,mx2; void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;} void dfs(int Fa,int t,int Ls,int sum) { int i; if (sum>mx) mx=sum,mx2=t; for (i=ls[t]; i; i=a[i][1]) if (a[i][0]!=Fa) dfs(t,a[i][0],(b[a[i][0]]>0)?b[a[i][0]]:Ls,sum+(b[a[i][0]]>0 && b[a[i][0]]!=Ls)); } int main() { #ifdef file freopen("CF1442E.in","r",stdin); #endif scanf("%d",&T); for (;T;--T) { scanf("%d",&n),len=0,memset(ls,0,(n+1)*4); fo(i,1,n) scanf("%d",&b[i]); fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j); mx=-1,dfs(0,1,b[1],b[1]>0); mx=-1,dfs(0,mx2,b[mx2],b[mx2]>0); printf("%d\n",mx/2+1); } fclose(stdin); fclose(stdout); return 0; }