首先定\(1\)为根节点,然后我们发现,如果全部的限制都是弯的,也就是\(x_i\)与\(y_i\)均不是两个点的LCA,则直接选择一个根节点就可以解决。
然后如果全部限制都是直的,仿照NOI2020 D1T2考虑一个dp,设\(f_{i,j}\)为处理了\(i\)子树内的节点,且当前往上最深的链为\(j\)的答案。容易用线段树优化到\(O(n\log n)\)转移。
但是真 的 需 要 吗?
我们发现这个东西每次只会加一,也就是说\(j\)最浅一定最优。然后状态就少了一维。
同时我们发现,\(j\)最浅的时候刚好对所有弯的限制贡献最大,也就是说两个贪心被统一了。
所以最后只要跑出方案数以后看看是不是能把全部弯的覆盖即可。
时间复杂度\(O(n+q)\)
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=3e5+5,M=10+5,K=1e5+5,mod=998244353,Mod=mod-1,INF=2e9+7;const db eps=1e-5;mt19937 rnd(263082);
int Fl[N],Ans,g[N],X[N],Y[N],n,m,k,x,y,z,d[N],Bg[N],Bh,En[N],Sum[N];vector<int> S[N],Q[N];
void Make(int x,int La){d[x]=d[La]+1;Bg[x]=++Bh;for(int i:S[x]) i^La&&(Make(i,x),0);En[x]=Bh;}
void GA(int x,int La){g[x]=-1e9;for(int i:S[x]) GA(i,x),Fl[i]&&(g[x]=-1e9),g[x]=max(g[x],Fl[x]?-INF:g[i]),Fl[x]|=Fl[i];if(g[x]==d[x]-1) g[x]=-1e9,Ans++,Sum[Bg[x]]++,Fl[x]=1;for(int i:Q[x]) g[x]=max(g[x],d[i]);}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d",&n,&m);for(i=2;i<=n;i++) scanf("%d",&x),S[x].PB(i);Make(1,0);
for(i=1;i<=m;i++) {
scanf("%d%d",&X[i],&Y[i]);d[X[i]]>d[Y[i]]&&(swap(X[i],Y[i]),0);
if(Bg[Y[i]]>=Bg[X[i]]&&Bg[Y[i]]<=En[X[i]]){if(d[Y[i]]-d[X[i]]==1) {puts("-1");return 0;}Q[Y[i]].PB(X[i]); }
}GA(1,0);for(i=1;i<=n;i++)Sum[i]+=Sum[i-1];int Fl=0;for(i=1;i<=m;i++){
if(Bg[Y[i]]>=Bg[X[i]]&&Bg[Y[i]]<=En[X[i]]) continue;
if(Sum[En[X[i]]]-Sum[Bg[X[i]]-1]+Sum[En[Y[i]]]-Sum[Bg[Y[i]]-1]==Ans) Fl=1;
}printf("%d\n",Ans+Fl);
}
标签:Bg,int,Squid,CF1610H,Game,&&,using,Fl,define
From: https://www.cnblogs.com/275307894a/p/16905409.html