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

  • 相关阅读:
    CSU 1333 Funny Car Racing
    FZU 2195 检查站点
    FZU 2193 So Hard
    ZOJ 1655 FZU 1125 Transport Goods
    zoj 2750 Idiomatic Phrases Game
    hdu 1874 畅通工程续
    hdu 2489 Minimal Ratio Tree
    hdu 3398 String
    洛谷 P2158 [SDOI2008]仪仗队 解题报告
    POJ 1958 Strange Towers of Hanoi 解题报告
  • 原文地址:https://www.cnblogs.com/wang9897/p/10455764.html
Copyright © 2011-2022 走看看