补题1:龙龙送外卖
题意:
![](https://img-blog.csdnimg.cn/img_convert/62ad41ba417be4bc90a8f52ec999c428.png)
![](https://img-blog.csdnimg.cn/img_convert/0e31ba521b69d550741c8e5f7093cbc7.png)
做法:思维--遍历方式,从输入的点往外卖点遍历,或标记过的点。回溯的时候更新深度!
//到达了最后一个送货点之后不用返回根结点.那么之前到达的点都是要折返点,那么就最后才送最深点节点。 //还有就是如果在去节点8点时候,途径了节点2,那么这个时候去节点2的路可以忽略,因为是顺路的。 //一边读入一边遍历,从输入的点开始,往上走.直到到达外卖站或到达一个被标记过的点,停止. // 回溯的时候更新深度!! 而且dfs不是void类型,要返回该次点增加的代价.并且要更新deepest.输出sum-deepest即可.
int n,q,s,ans=0,deepest=0;
int fa[100005],depth[100005];
unordered_map<int,bool> mark;
int dfs(int cur,int d){
if(cur==s||mark[cur]){
deepest=max(deepest,depth[cur]+d);
return 2*d;
}
int res=0; //res
res+=dfs(fa[cur],d+1);
depth[cur]=depth[fa[cur]]+1;
mark[cur]=1;
deepest=max(deepest,depth[cur]);
return res;
}
void solve(){ //补7-11--龙龙送外卖--思维-遍历方式
//到达了最后一个送货点之后不用返回根结点.那么之前到达的点都是要折返点,那么就最后才送最深点节点。
//还有就是如果在去节点8点时候,途径了节点2,那么这个时候去节点2的路可以忽略,因为是顺路的。
//一边读入一边遍历,从输入的点开始,往上走.直到到达外卖站或到达一个被标记过的点,停止.
// 回溯的时候更新深度!!
cin>>n>>q;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(x==-1) s=i;
else fa[i]=x;
}
while(q--){
int x;
cin>>x;
ans+=dfs(x,0);
cout<<ans-deepest<<endl;
}
}
补题2:智能护理中心统计
题意:
![](https://img-blog.csdnimg.cn/img_convert/a66a8f06864936968b6aef302347a0d4.png)
![](https://img-blog.csdnimg.cn/img_convert/458600fd758096c831c1b1a7f71260bd.png)
10 23
EAST CNTR
ZJ EAST
SD EAST
WEST CNTR
SX WEST
HZ ZJ
JN SD
2 JN
8 JTH
6 XAHP
4 ZDYH
5 ZDYH
ZDYH HZ
HUZ ZJ
JX ZJ
1 JX
3 JN
WZ ZJ
XAHP XIAN
XIAN SX
YL SX
JTH XIAN
7 XAHP
Q EAST
T 1 YL
Q EAST
Q SX
T 8 ZDYH
Q HZ
Q HUZ
T 10 XAHP
Q CNTR
E
以上为输入。。
输出:
5
4
4
3
0
9
做法:首先要把输入第一次出现的机构先哈希h[机构]=curhash.如果输入的是机构+机构,那么按照高层向低层建图vct1.如果是人+机构,那么记录机构人数的mp2[机构]++且mp1[老人]=h[机构].但是因为输入可能不是一棵树,可能是森林,那么就有多个最高层机构(即根节点,入度为0).那么可以开一个mp3来判断,哪些出现过的机构,入度是0的。后面dfs遍历mp3中各个根节点,并且更新mp2的人数---到这里初始处理完成。之后读入操作。如果是Q,直接输出mp2[ask]。如果是转移,有两种可能,老人可能是新来的,原本不属于任何机构,那么只需要mp2向上增加。如果老人原本属于某个机构,那么原机构mp2向上减,新机构mp2向上增加.并且修改mp1为新机构。因为这里要低层向高层更新,刚才建图的vct1是高层向低层,那么需要回到上面输入再建一个图vct2,低层向高层。即vct1和vct2是反向的。不建为一个无向图是因为进行特定反向遍历的时候,不能分辨哪个点是高层,哪个是低层,所以干脆分开建图。 赛后补题时候没有看题解,写的思路和赛时是完全一样的,但是比赛时更加清晰(没想到一发就过了,不用调错(只有dfs,mp2更新那里有一点错,一下就改正了))。赛时虽然思路是这么个思路,但是没有实现好,写的自己有点晕,导致没写出来,还是要保持高度专注和仔细吧。ps:这题更上一题""龙龙送外卖""都有dfs遍历,回溯的时候更新节点的值.
unordered_map<string,int> h;
vector<int> vct1[100005],vct2[100005];
unordered_map<int,int> mp1,mp2; //mp1[老人]=机构 mp2[机构]=人数
unordered_map<int,bool> mp3; //找到根节点
int curhash=0;
int dfs(int x){
int res=0;
for(auto v:vct1[x]){
res+=dfs(v);
}
mp2[x]+=res; //for之后更新现在的节点
return mp2[x];
}
void up(int x,int op){
if(op==1){ //加
mp2[x]++;
for(auto boss:vct2[x]) up(boss,1);
}
else{ //减
mp2[x]--;
for(auto boss:vct2[x]) up(boss,0);
}
}
void solve(){ //补7-12 智能护理中心统计
//先建机构和机构的关系树.关系树可能会是森林,可能有多个根节点-入度为0。每棵树都要进行处理.
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
string str1,str2;
cin>>str1>>str2;
if(str1[0]>='1'&&str1[0]<='9'){ //人+机构
if(h[str2]==0) h[str2]=++curhash;
mp1[stoi(str1)]=h[str2];
mp2[h[str2]]++;
}
else{ //机构+机构
if(h[str1]==0) h[str1]=++curhash;
if(h[str2]==0) h[str2]=++curhash;
mp3[h[str1]]=1;
if(mp3[h[str2]]==0) mp3[h[str2]]=0;
vct1[h[str2]].emplace_back(h[str1]); //高层到低层
vct2[h[str1]].emplace_back(h[str2]); //低层到高层
}
}
for(auto m3:mp3){ //从根节点进入,往下dfs
if(m3.second==0) dfs(m3.first);
}
// for(auto h0:h){
// cout<<h0.first<<":"<<mp2[h0.second]<<endl;
// }
while(1){
char op;
cin>>op;
if(op=='E') break;
if(op=='Q'){
string ask;
cin>>ask;
cout<<mp2[h[ask]]<<endl;
}
else{
int per;
string to;
cin>>per>>to;
if(mp1[per]==0){ //如果老人一开始没有所属
up(h[to],1); //加
mp1[per]=h[to];
}
else{
up(mp1[per],0); //减
up(h[to],1); //加
mp1[per]=h[to]; //更改老人的所属
}
}
}
}