本文共 2078 字,大约阅读时间需要 6 分钟。
题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值。
考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1.
考虑树形DP。
用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上。
那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的部分)。
那么如果从父亲向上的部分是不完全子树呢,那等价于从这颗不完全子树上的一个深度最小的点做上面的计算一下。所以不需要考虑从父亲向上的部分是不完全子树这个情况。
时间复杂度O(nlogn).
# include # include # include # include # include # include # include # include # include # include # include # include using namespace std;# define lowbit(x) ((x)&(-x))# define pi acos(-1.0)# define eps 1e-8# define MOD 1000000007# define INF 1000000000# define mem(a,b) memset(a,b,sizeof(a))# define FOR(i,a,n) for(int i=a; i<=n; ++i)# define FO(i,a,n) for(int i=a; i PII;typedef vector VI;# pragma comment(linker, "/STACK:1024000000,1024000000")typedef long long LL;int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}const int N=200005;//Code begin...struct Edge{ int p, next;}edge[N<<1];int node[N], head[N], cnt=1, dp[N], date[N], siz[N], tag[N], sum, n, K, ans;bool flag[N];void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}void dfs1(int x, int fa, int val){ siz[x]=1; if (node[x] =val) { if (dp[v]>f) s=f, f=dp[v]; else if (dp[v]>s) s=dp[v]; } } dp[x]+=f; if (node[x]>=val) { if (tag[x]==sum) ans=max(ans,dp[x]+s+n-siz[x]); else ans=max(ans,dp[x]+s); }}bool check(int x){ mem(siz,0); mem(dp,0); mem(flag,false); mem(tag,0); sum=ans=0; dfs1(1,0,x); dfs2(1,0,x); return ans>=K;}int main (){ int u, v; scanf("%d%d",&n,&K); FOR(i,1,n) scanf("%d",node+i), date[i]=node[i]; FO(i,1,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u); sort(date+1,date+n+1); int l=1, r=n+1, mid; while (l >1; if (l==mid) break; if (check(date[mid])) l=mid; else r=mid; } printf("%d\n",date[l]); return 0;}
转载于:https://www.cnblogs.com/lishiyao/p/6971255.html