【DFS序(求子树)】

【DFS序(求子树)】

image

性质

入序和出序之间的编号是该节点的子树
->叶节点的出序和入序编号相等

模版代码

int in[N],out[N];//in表示首次访问的编号,out表示访问结束的编号
bool st[N];//标记节点访问状态
int tim=0;
void dfs(int u,int fa){
      if(st[u]) return;
      in[u]=++tim;
      st[u]=1;
      for(auto son:g[u]){
	    if(son==fa) continue;
            dfs(son,u);
      }
      st[u]=0;
      out[u]=tim;
}

题目整理

The Game (Easy Version)

https://codeforces.com/contest/2062/problem/E1

思路

选次大点,逼对手选最大点
前提是:次大点子树外仍有最大点

image
检查子树外的w有没有比子树的w大

代码

注意邻接表用vector存就行
链式前向星 会T(没救了
image

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=400010,M=N*2;
int t,n,w[N];
vector<int> e[N];
/*
【思路】
找子树外(dfs序)比子树权值大的点->前缀/后缀和维护
*/
int dfn[N],nfd[N],low[N],pre[N],suf[N];
bool ed[N];
int tim=0;
int mx=0;
void dfs(int u){
      if(ed[u]) return;
      dfn[u]=++tim;
      nfd[tim]=u;
      ed[u]=1;
      for(auto j:e[u]){
            dfs(j);
      }
      low[u]=tim;
      ed[u]=0;
}
void solve(){
      cin>>n;
      memset(ed,0,sizeof ed);
      mx=0;
      tim=0;
      for(int i=1;i<=n;i++){
            e[i].clear();
            cin>>w[i];
      }
      for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            e[u].push_back(v);
            e[v].push_back(u);
      }
      dfs(1);
      //求dfs序下前缀的最大值
      pre[0]=0;
      suf[n+1]=0;
      for(int i=1;i<=n;i++) pre[i]=max(pre[i-1],w[nfd[i]]);
      for(int i=n;i>=1;i--) suf[i]=max(suf[i+1],w[nfd[i]]);
      //子树外+值大
      for(int i=1;i<=n;i++){
            if(max(pre[dfn[i]-1],suf[low[i]+1])>w[i] && w[i]>w[mx]) mx=i;
      }
      cout<<mx<<endl;
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}
posted @ 2025-01-29 12:12  White_ink  阅读(8)  评论(0)    收藏  举报