BZOJ 3037 创世纪
题解:
首先从基环树上的环上选两个点x,y
断开x,y之间的边,然后做树形DP.
设f[x]为选x的情况下的最大值,g[x]为不选x的情况下的最大值.
分两种情况讨论,
1.选x,则y一开始就处于被支配状态,在计算y的f[]函数值时需要特判.
2.不选x,按正常DP做即可.
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 #define ll long long 5 #define FILE "dealing" 6 #define up(i,j,n) for(int i=j;i<=n;i++) 7 #define db long double 8 #define pii pair<int,int> 9 #define pb push_back 10 #define mem(a,L) memset(a,0,sizeof(int)*(L+1)) 11 template<class T> inline bool cmin(T& a,T b){return a>b?a=b,true:false;} 12 template<class T> inline bool cmax(T& a,T b){return a<b?a=b,true:false;} 13 template<class T> inline T squ(T a){return a*a;} 14 const ll maxn=2000100+10,inf=1e9+10,limit=1e7; 15 int read(){ 16 int x=0,f=1,ch=getchar(); 17 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 18 while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 19 return x*f; 20 } 21 int n; 22 vector<int> t[maxn]; 23 int f[maxn],g[maxn],to[maxn]; 24 int vis[maxn]; 25 int rt,rt2,q[maxn],top=0; 26 void dfs(int x){ 27 q[++top]=x; 28 vis[x]=1; 29 if(!vis[to[x]])dfs(to[x]); 30 else { 31 rt=x; 32 rt2=to[x]; 33 } 34 } 35 void dfs2(int x){ 36 vis[x]=1; 37 for(int i=0;i<t[x].size();i++) 38 if(!vis[t[x][i]])dfs2(t[x][i]); 39 if(!vis[to[x]])dfs2(to[x]); 40 } 41 //f[x] 选 g[x] 不选 42 int flag=0; 43 void dfs1(int x){//选rt 44 f[x]=1,g[x]=0;int Max=-inf; 45 for(int i=0;i<t[x].size();i++){ 46 int y=t[x][i];if((x==rt2&&y==rt))continue; 47 dfs1(y); 48 f[x]+=f[y]; 49 g[x]+=f[y]; 50 cmax(Max,g[y]-f[y]); 51 } 52 f[x]+=Max; 53 if(x==rt2&&flag)f[x]-=Max; 54 cmax(f[x],0); 55 } 56 57 int main(){ 58 freopen(FILE".in","r",stdin); 59 freopen(FILE".out","w",stdout); 60 n=read(); 61 up(i,1,n){ 62 to[i]=read(); 63 t[to[i]].push_back(i); 64 } 65 int ans=0; 66 up(i,1,n){ 67 if(vis[i])continue; 68 top=0;dfs(i); 69 while(top)vis[q[top--]]=0; 70 dfs2(i); 71 int Ans=0; 72 flag=1; 73 dfs1(rt); 74 cmax(Ans,g[rt]); 75 flag=0; 76 dfs1(rt); 77 cmax(Ans,f[rt]); 78 ans+=Ans; 79 } 80 printf("%d\n",ans); 81 return 0; 82 }