zoukankan      html  css  js  c++  java
  • [BZOJ]2068: [Poi2004]SZP

    题解: 根据题目的特殊性 我们考虑基环树  对于非树边uv我们对深度较高的点分情况讨论 取或者不取  然后做个树dp就行了

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=1e6+1100;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    const int inf=1e9;
    struct edge{int t;edge*next;}e[MAXN],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    vector<pii>circle;
    bool vis[MAXN],c[MAXN];
    int n;
    int base,Base;
    int dp[MAXN][2],dp1[MAXN][2];
    
    void tarjan(int x,int y){
        circle.pb(mp(x,y));
    }
    
    void dfs(int x){
        vis[x]=1;
        link(x){
    	if(j->t==base)tarjan(x,base);
    	else if(!vis[j->t])dfs(j->t);
        }
    }
    
    void _dfs(int x){
        bool flag=0,flag1=0;int minn=inf;
        link(x){
    	if(j->t==base)continue;
    	_dfs(j->t);
    	flag1=1;
    	dp[x][0]+=max(dp[j->t][0],dp[j->t][1]);
    	if(dp[j->t][0]>=dp[j->t][1])flag=1;
    	if(j->t!=Base)minn=min(minn,dp[j->t][1]-dp[j->t][0]);
        }
        if(x==Base||flag)dp[x][1]=dp[x][0]+1;
        else dp[x][1]=max(0,dp[x][0]-minn+1);
    }
    
    void __dfs(int x){
        bool flag=0,flag1=0;int minn=inf;
        link(x){
    	if(j->t==base)continue;
    	__dfs(j->t);
    	flag1=1;
    	dp1[x][0]+=max(dp1[j->t][0],dp1[j->t][1]);
    	if(dp1[j->t][0]>=dp1[j->t][1])flag=1;
    	minn=min(minn,dp1[j->t][1]-dp1[j->t][0]);
        }
        if(flag)dp1[x][1]=dp1[x][0]+1;
        else dp1[x][1]=dp1[x][0]-minn+1;
    }
    
    int main(){
        n=read();
        inc(i,1,n){int x=read();add(x,i);}
        inc(i,1,n)if(!vis[i]){base=i;dfs(i);}
        int ans=0;
        for(int i=0;i<circle.size();i++){
    	int x=circle[i].first;int y=circle[i].second;
    	base=y;Base=x;
    	_dfs(y);__dfs(y);
    	ans+=max(dp[y][0],max(dp1[y][1],dp1[y][0]));
        }
        printf("%d
    ",ans);
    }
    

      

    2068: [Poi2004]SZP

    Time Limit: 20 Sec  Memory Limit: 162 MB
    Submit: 258  Solved: 118
    [Submit][Status][Discuss]

    Description

    Byteotian 中央情报局 (BIA) 雇佣了许多特工. 他们每个人的工作就是监视另一名特工. Byteasar 国王需要进行一次秘密行动,所以他要挑选尽量多的信得过的特工. 但是这项任务是如此的机密以至于所有参加行动的特工都必须至少被另一名没有参加任务的特工所监视( 就是说如果某个特工参加了行动,那么原先监视他的那些特工中至少要有一个没有参加进行动). 给出监视任务的详情,要求计算最多能有多少个特工参与其中.

    Input

    第一行只有一个整数, n – 特工的总数, 2 <= n <= 1000000. 特工从1 到 n编号. 接下来n行每行一个整数ak 表示特工k将要监视特工ak , 1 <= k <= n, 1 <= ak <= n, ak <> k.

    Output

    打印一个数,最多能有多少特工参加入这个任务.

    Sample Input

    6
    2
    3
    1
    3
    6
    5

    Sample Output

    3

    HINT

  • 相关阅读:
    分式函数的变换源
    分式之殇
    两条直线的位置关系
    数列专题思维导图
    数列通项公式思维导图
    函数与导数思维导图
    三角函数思维导图
    函数与初等函数思维导图
    集合思维导图
    npm包发布正式和测试版
  • 原文地址:https://www.cnblogs.com/wang9897/p/10455764.html
Copyright © 2011-2022 走看看