2017年河南省ACM省赛 Problem B: 情报传递

来源:互联网 发布:240光束灯编程视频教程 编辑:程序博客网 时间:2024/06/13 12:54

问题 B: 情报传递

时间限制: 2 Sec  内存限制: 128 MB

题目描述

抗日战争时期,在国共合作的大背景下,中共不断发展壮大,其情报工作也开始由获取警报性、保卫性信息,向获取军政战略性情报转变。各系统情报组织遵循"荫蔽精干,长期埋伏,积蓄力量,以待时机"的隐蔽战线工作方针,开展了卓有成效的情报工作。

***特科组是中共情报工作的一个杰出范例,它以点为主、系统延伸、分散辐射的力量格局,异地领导、分头派遣、单线联系的组织形式。以打入、拉出、统战联络、内线为主的工作方式,形成了一个传递信息隐蔽、效用及时、形式多样的情报网络。

***特科组的情报人员共有N人,其代号分别为0,1,……,N-1。 0号是最高领导人,特工之间有一套严格的单线联络程序,即,每个特工人员只有一个上线,他获得的情报需层层上传递到0号手里,由0号发报出去。

特工i在传递情报时,若通往到0号的通道尚未建立,则需要建立一级级单线通道;若他的上线已建立好通道,只需建立两人通道,信息发送给上线;依次类推。若特工i已建立好到0号的通道,则直接发出情报。日伪统治中心南京,既是情报来源丰富的地方,又是特工人员活动最危险的地方。因此,一旦某个特工处于不安全状态,他必须马上撤离,同时他的所有下线(处在通道上的一级级下线)也一同撤离。

已知***特科组的组织结构,你的任务是计算,当某特工i需要发送情报时,最少需要建立几个情报人员的通道;当某特工i处于不安全状态时,最少需要撤离多少人员。

输入

第一行一个整数:  N           ( 1≤N ≤5060 )

接下来一行有N-1 个整数,  A1 A2 ……An-1  ,其中Ai是编号i的上线。

下一行一个整数:  M         表示有M个状态,( 1≤M ≤5060 )

接下来有M行 :有两种形式:  Send i    特工i处于要发送情报状态;

                             Danger i  特工i处于不安全状态

输出

输出占M行 ,对于Send i,输出最少需要建立通道的情报人员数,若特工i处于通道线上,输出0;

对于Danger i,输出最少需要撤离多少人员,若特工i不处于通道线上,则输出0.

样例输入

100 1 2 1 3 0 0 3 210Send 0Send 3Danger 2Send 7Send 5Send 9Danger 9Send 4Send 1Send 9

样例输出

1321311101

分析

根据题目可以知道最初所有的通道都是未建立的,而且在前面的情况中建立之后,后面就不用再计算这些已经存在的,需要建立通道的情报人员数就相当于最少需要建立的通道数,最少需要撤离多少人员就相当于求出需要断开多少条已经建立的通道,而且0号本身传递也是要建立通道才能传递的。断了之后的通道,需要重新建立。

代码

#include <algorithm>#include <iostream>#include <string>#include <vector>#include <stack>#include <queue>#include <set>#include <map>#include <cstdlib>#include <cstring>#include <cstdio>#include <cmath>using namespace std;vector<int>v[5100];//存放各个特工的低一级的下线int N,M;int s[5100];//存放各个特工的上一级bool vis[5100];//存放各个特工的通道的建立情况int Own;//记录需要逃离的人员数void Send(int num){    int sum=0;//记录需要建立的通道数    while(!vis[num]&&num!=-1)//因为把0号特工定义为了-1,所以如果num==1就说明从给num号建立到了最高领导人    {        sum++;//总数加1        vis[num]=true;        num=s[num];//将num变为num的上级继续判断    }    printf("%d\n",sum);}void Danger(int num){    for(int i=0; i<v[num].size(); i++)//挨个判断num的下一级的断开情况,并用递归来判断下一级的各个下线    {        if(vis[v[num][i]])        {            vis[v[num][i]]=false;//将此条通道断开            Own++;//断开数加1            Danger(v[num][i]);//递归判断num下线的下线的情况        }    }}int main(){    int i;    scanf("%d",&N);    s[0]=-1;//将0定位-1,来结束后面记录通道数时的循环    for( i=1; i<N; i++)    {        scanf("%d",&s[i]);        v[s[i]].push_back(i);//将各个下线存入到其上线对应的动态数组中    }    memset(vis,false,sizeof(vis));//将所用通道初始化为断开    scanf("%d",&M);    char str[10];    int num;    for(i=1; i<=M; i++)    {        scanf("%s",&str[0]);        scanf("%d",&num);        if(str[0]=='S')//通过首字母来判断是Send的情况还是Danger的情况        {            Send(num);//调用Send函数        }        else        {            if(!vis[num])//如果该通道不是断开,就说明它通往0号的通道已经全部建立            {                printf("0\n");                continue;            }            Own=1;//num到上一级的通道也需要断开,而Danger函数只记录了各个位置断开时其低一级需要断开的数目,所以初始为1            vis[num]=false;//断开这条通道            Danger(num);            printf("%d\n",Own);        }    }    return 0;}


阅读全文
1 0