至于WYF大概是谁,不必多说,结合时事,人渣必须从严处理,从重判刑;代码量比较大,各位耐心看一下

WYF互相追逐的头



题目的阅读量比较大,而且数据比较清奇,但是我们可以知道的是每一个头都在尽力追逐自己喜欢的那个头,因此和它同方向(也就是不知道往哪移动)必然就是早晚的事情。

所以如果互相追逐的头之间的追逐关系形成一个环的话,WYF的这些头到最后必然会不知道往哪去,因此只要我们能够判环,则此题可以解之。

但是我们在解题的时候要注意一点:输入的数据描述种存在一种可能性,使得两群头之间不存在任何追逐的关系,针对这种情况,解决方案就是将联通的节点之间打上标记,然后没有被标记的节点再次进行判环,其实只要找到了一个环就立刻输出即可,这道题特判,判分很松。

下放代码,代码量两题都很大,但是MAFIJA的部分代码可以完全抄WYF的头的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct edge{int to,nxt;
};
int hlis[300000];
int hhp;
edge eds[600000];
int bef[300000];
int hd[300000];
int tl[300000];
int hp;
int chase,head;
bool vish[200001];
bool vis[200001];
int hsec;
void bud(int fr,int to){if(hd[fr]==-1){hd[fr]=hp;tl[fr]=hp;eds[hp].to=to;eds[hp].nxt=-1;hp++;}else{eds[tl[fr]].nxt=hp;tl[fr]=hp;eds[hp].to=to;eds[hp].nxt=-1;hp++;}
}
void df(int now,int up){if(!vis[now]){vis[now]=true;for(int a = hd[now];a!=-1;a=eds[a].nxt){if(eds[a].to!=up)df(eds[a].to,now);}}
}
int ph(int now,int up){if(!vish[now]){bef[now]=up;vish[now]=true;int rt;for(int a = hd[now];a!=-1;a=eds[a].nxt){if(eds[a].to!=up)rt=ph(eds[a].to,now);if(rt!=-1){return rt;}}return -1;}else{hsec = now;return up;}
}
void u(int now,int tar){if(now==tar){hlis[hhp]=now;hhp++;return;}else{hlis[hhp]=now;hhp++;u(bef[now],tar);}
}
int chasing[200001];
int main(){scanf("%d",&head);memset(hd,-1,sizeof hd);memset(tl,-1,sizeof tl);memset(chasing,0,sizeof chasing);for(int a = 1;a<=head;a++){scanf("%d",&chase);if(chase<a&&chasing[chase]==a){;}else{bud(a,chase);bud(chase,a);chasing[a]=chase;}}int huana;for(int a = 1;a<=head;a++){if(!vis[a]){memset(vis,false,sizeof vis);df(a,-1);memset(vish,false,sizeof vish);huana=ph(a,-1);if(huana!=-1){hhp = 0;u(huana,hsec);cout << hhp<<endl;for(int x = 0;x<hhp;x++){cout <<hlis[x]<<" "; }break;}}}int x,y;for(int a = 0;a<head;a++){scanf("%d%d",&x,&y);}return 0;
} 

MAFIJA

简单聊一下题意和本质。狼人和民众数量未知,每个人之间互相揭发,狼人知道谁是什么角色,因此不会揭发同伙,平民则是在随机揭发,他们的揭发没有任何价值。

由此可见我们可以忽略平民的揭发,狼人揭发的一定是平民,但是我们现在并不知道狼人和平民谁是谁,这就是问题。

但是根据题意,我们可以发现:揭发狼人的和狼人所指的都是平民,这不就有点像无向图的关系嘛~每人揭发一人,构成基环树,可以找出来环然后每个环内的节点作为根节点,找出来根节点作狼人和作平民时的最大狼人数量。这里其实就是一个树形的动态规划(虽然做题的时候我并没有意识到,但我写出来了),先将子树根节点作狼人/平民时候的狼人最大数量算出来,然后在上一个根节点得出同类型的两个值,叶子节点上作为狼人时狼人数量是1,不做狼人时狼人数量是0,上一级节点如果作为平民,则下级节点既可以是狼人也可以是平民,因此我们取两个值中的最大值,如果作为狼人,则下一个节点只能取平民,然后狼人数量再+=1(因为上级节点作为狼人的数量应该计入)以此类推,直到环上的节点的最大狼人数量都被算出来,这道题就做出来了一大半。

然后我们手里就拿到了一个大概率不算很长,数据已经算好的环。这个时候我们根据狼人和狼人不能相邻的特性,随机切断这个环,再将任意一个端点作为树的根节点,而这个节点会被确定为平民,这样环中的上一个节点的种类就不再受到限制了。继续转移方程,最后在根节点中作为人民,得出一个ans_a。

那么如果真正的最优方案中根节点应该做狼人应该怎么办呢?很简单,因为如果这个点是狼人那么旁边的点一定是平民,因此在将环中的根节点错位一下,将旁边得点当成平民重复上一段的运算一遍,取两个方案中答案的最大值加在ans里,在程序考虑所有点后输出。

最后在提醒一点:本题和上一道题一样,存在两个子图不连通的情况,针对这种情况需要染色+循环找到未被设计的点,因此不少程序段会重复进行,数组数据需要注意清空
放上代码,这道题的代码我保守估计和上一个代码的查重率会在50%以上,剩下的代码写出来不多,不过挺费脑力,少一个环节都会爆蛋;

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct edge{int to,nxt;
};
int asrm[500001];
int asbt[500001];
int hlis[500001];
int hhp;
edge eds[1000000];
int bef[500001];
int hd[500001];
int tl[500001];
int hp;
int chase,head;
bool vish[500001];
bool vis[500001];
int hsec;
void bud(int fr,int to){if(hd[fr]==-1){hd[fr]=hp;tl[fr]=hp;eds[hp].to=to;eds[hp].nxt=-1;hp++;}else{eds[tl[fr]].nxt=hp;tl[fr]=hp;eds[hp].to=to;eds[hp].nxt=-1;hp++;}
}
void df(int now,int up){if(!vis[now]){vis[now]=true;for(int a = hd[now];a!=-1;a=eds[a].nxt){if(eds[a].to!=up)df(eds[a].to,now);}}
}
int ph(int now,int up){if(!vish[now]){bef[now]=up;vish[now]=true;int rt;for(int a = hd[now];a!=-1;a=eds[a].nxt){if(eds[a].to!=up)rt=ph(eds[a].to,now);if(rt!=-1){return rt;}}return -1;}else{hsec = now;return up;}
}
void u(int now,int tar){if(now==tar){vish[now]=true;hlis[hhp]=now;hhp++;return;}else{vish[now]=true;hlis[hhp]=now;hhp++;u(bef[now],tar);}
}
int chasing[500001];
int ans = 0;
int dphrm[500001];
int dphbt[500001];
void dfdp(int now,int up){for(int a = hd[now];a!=-1;a=eds[a].nxt){if(eds[a].to!=up&&!vish[eds[a].to]){dfdp(eds[a].to,now);asrm[now]+=max(asrm[eds[a].to],asbt[eds[a].to]);asbt[now]+=asrm[eds[a].to];}}asbt[now]+=1;return;
}
int main(){scanf("%d",&head);memset(asrm,0,sizeof asrm);memset(asbt,0,sizeof asbt);memset(hd,-1,sizeof hd);memset(tl,-1,sizeof tl);memset(chasing,0,sizeof chasing);for(int a = 1;a<=head;a++){scanf("%d",&chase);if(chase<a&&chasing[chase]==a){;}else{bud(a,chase);bud(chase,a);chasing[a]=chase;}}int huana;for(int a = 1;a<=head;a++){if(!vis[a]){df(a,-1);memset(vish,false,sizeof vish);huana=ph(a,-1);if(huana!=-1){//有环,错开DP memset(vish,0,sizeof vish);hhp = 0;u(huana,hsec);for(int s = 0;s<hhp;s++){dfdp(hlis[s],-1);dphrm[s]=asrm[hlis[s]];dphbt[s]=asbt[hlis[s]];}for(int s = hhp-2;s>=0;s--){dphrm[s]+=max(dphrm[s+1],dphbt[s+1]);dphbt[s]+=dphrm[s+1];}int ansa = dphrm[0];for(int s = 0;s<hhp;s++){dphrm[s]=asrm[hlis[s]];dphbt[s]=asbt[hlis[s]];}for(int s = hhp;s>0;s--){dphrm[s]=dphrm[s-1];dphbt[s]=dphbt[s-1];}dphrm[0]=dphrm[hhp];dphbt[0]=dphbt[hhp];dphrm[hhp]=0;dphbt[hhp]=0;for(int s = hhp-2;s>=0;s--){dphrm[s]+=max(dphrm[s+1],dphbt[s+1]);dphbt[s]+=dphrm[s+1];}int ansb = dphrm[0];ans+=max(ansa,ansb);}else{//没环,直接DP memset(vish,0,sizeof vish);dfdp(a,-1);ans+=max(asbt[a],asrm[a]);}}}cout << ans;return 0;
}

“基环树”的简单应用——MAFIJA和WYF互相追逐的头题解相关推荐

  1. CodeForces - 1252L Road Construction(基环树+有源汇有上下界的最大流)

    题目链接:点击查看 题目大意:给出 n 个节点,再给出 n 个出边,保证所有的边能将 n 个点连通,每条出边可以用 m[ i ] 种材料选择其一建造,然后有 k 个工人,每个工人只可以使用一种材料建造 ...

  2. 基环树一些有趣的事情

    基环树,就是有一个环的树.有向基环树又分内向和外向基环树,当然也有无向的. 最近遇到的基环树真不少.有些题目赤裸裸的就告诉你,"给出一棵基环树(环套树)",但是有的题会有一些标志. ...

  3. [TJOI2013]拯救小矮人(反悔贪心证明),「ICPC World Finals 2019」Hobson 的火车(基环树,差分)

    2021-09-07 test [TJOI2013]拯救小矮人 「ICPC World Finals 2019」Hobson 的火车 [TJOI2013]拯救小矮人 luogu4823 考试题目的数据 ...

  4. 数据结构之基环树——骑士,Island,旅行加强版,Number of Simple Paths,Traffic Network in Numazu,Card Game

    文章目录 [ZJOI2008]骑士 [IOI2008] Island [NOIP2018 提高组] 旅行 加强版 CF1454E Number of Simple Paths Traffic Netw ...

  5. AtCoder Beginner Contest 266(C- G)「判凸包」「dp」「期望」「基环树」「组合数」

    abc好好好. C - Convex Quadrilateral (atcoder.jp) 思路: 判凸包,向量叉积×=|a|*|b|*sin.叉积<0即角>180°. (可以勉勉强强算我 ...

  6. loj 523 「LibreOJ β Round #3」绯色 IOI(悬念) 霍尔定理+基环树+线段树

    题目分析 神仙题(确信) 首先,j−aij-a _ ij−ai​和ai−ja _ i-jai​−j互为相反数,若其中最小值为bib _ ibi​,则一个为bib _ ibi​一个为m−bim-b _ ...

  7. 【暖*墟】#动态规划# 基环树DP的学习与练习

    因为弃置了 四边形不等式优化 ,所以DP的任务还剩下 基环树DP / 插头DP / 动态DP 当然,树形DP / 状压DP / 数位DP / 斜率优化DP 也还是要练习的...... 一 . 基环树的 ...

  8. 【基环树DP】[NOI2012]迷失游乐园

    题目描述 Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多 ...

  9. CodeForces - 1454E Number of Simple Paths(基环树+思维)

    题目链接:点击查看 题目大意:给出一棵 n 个点的基环树,现在需要求所有长度大于等于 1 的路径个数 题目分析:对于所有的路径 ( x , y ) 可以分成下列两种情况来考虑: 路径不会经过环上的边: ...

最新文章

  1. php导出excel格式数据
  2. html 写一个日志控件 查看log
  3. android工程中让人很不爽的“×××警告”
  4. Python3实现邮件群发
  5. 2018.12.12
  6. Android app native代码性能分析
  7. linux l文件共享,llinux服务器文件共享的一种简单的方法
  8. TypeScript BigInt
  9. Java 设计模式之代理模式
  10. 基于vue的nuxt框架cnode社区服务端渲染
  11. 变频器调试工具:ABB Drive Composer
  12. 分享一个超厉害的网站,几乎解决一切command not found问题
  13. 如何隐藏C/C++编译生成的函数符号
  14. 计算机音乐谱一壶老酒,一壶老酒简谱(歌词)-陆树铭演唱-沈公宝曲谱
  15. CC控制服务的设计和侦测方法综述
  16. 关于OLAP数据仓库的归纳总结
  17. android studio怎么改软件扫码界面_一文入门Android逆向
  18. 【概率题汇总】互联网公司概率面试题整理
  19. Matlab quiver函数用法 - 画矢量箭头图
  20. 单线激光雷达为什么这么火?

热门文章

  1. GUET网络渗透测试实验报告1
  2. 如何查询拟投期刊是否为EI收录期刊
  3. 91---Python 直角坐标系下绘制双曲线图像
  4. 基于android小区智能管理,基于Android的智能小区停车场设计
  5. 公理化体系降维打击1之补充(脱敏版本)再加俺老孙的故事(开头)
  6. **ubuntu安装ansible并且安装awx管理**
  7. 中国电信天翼物联科协分会成立,加速科技创新成果转化
  8. 英威腾伺服驱动器故障代码_英威腾伺服电机常见问题及解决方法
  9. 黄荣奎:如何快速、便捷开发小程序
  10. 100多个地理、测绘方面的数据网站