【DFS序(求子树)】
【DFS序(求子树)】
性质
入序和出序之间的编号是该节点的子树
->叶节点的出序和入序编号相等
模版代码
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
思路
选次大点,逼对手选最大点
前提是:次大点子树外仍有最大点
检查子树外的w有没有比子树的w大
代码
注意邻接表用vector存就行
链式前向星 会T(没救了
#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;
}