当前位置:   article > 正文

小美的朋友关系-美团2024年春招第一场笔试【技术】_[编程题]小美的朋友关系

[编程题]小美的朋友关系

题目分析:涉及到亲戚或者朋友关系,例如亲戚的亲戚是亲戚,朋友的朋友是朋友,敌人的敌人是朋友这类问题,几乎可以直接思考并查集。此题目显然也是并查集问题,但是题目的查询操作居然可以遗忘掉已有的关系再询问,这一点就很难处理。因为并查集可以并,但并没有删除操作。而且即便删除a和b的边,a和b仍然可能通过其他关系连通。解决这个问题是关键。

题解:为了解决遗忘关系后再查询的问题。此处使用了一种OI技巧,离线查询

离线查询就是把q个询问先保存起来,然后一次性处理他们,而不是按询问次序处理。

举个例子说明下,一个序列a1,a2,.......an,现在有q个查询q1,q2,q3.......,询问你前qi个数字的最大值,比如查询序列是5 3 2 7......,先得到前5个最大值,再得到前3个最大值,我们知道求前5个最大值过程中,一定是先求得前3个最大值,那么可以先把这套查询序列存起来排个序2 3  5 7 ,从前向后求最大值,求到2 3 5 7 时把答案存起来以备未来查询使用。

(1)前面m个关系先不要进行并查集建树运算,而是保存在一个set中(方便查询)。

(2)我们先把所有的q个询问都保存起来,将那些遗忘的关系都找出来,如果这个关系在前m个关系中存在,就将set中这个关系删除,不存在就是无效关系,也需标记一下(以后就不理这个关系了)。处理结束,set中保存的就是未来不会遗忘的关系,此时并查集建树。

(3)q个询问从后往前进行处理,如果是询问,就并查集中查找。如果qi是遗忘的关系,那么这个关系对于前面的q1至qi-1询问来说并没有遗忘,将其加入到并查集中。

(4)一些其他特殊的点。数据n=1e9,没法用数组存储并查集,只能用map来存储。样例很良心地给了一个需要特殊注意的点:遗忘的关系可能本就是不存在的;另外需要注意的是关系的对称性,关系(1,2)和(2,1)是相同的。

  1. #include <bits/stdc++.h>
  2. typedef long long ll;
  3. using namespace std;
  4. int n,m,q,op[100005][3];/**< op数组存储q个询问 */
  5. set<pair<int,int> > s;/**< 存储关系 */
  6. map<int,int>f;/**< 并查集数组用map存储,因为此题目数据范围是1e9,不能用途数组 */
  7. int findx(int x)/**< 并查集查函数 */
  8. {
  9. if(f[x]==0)/**< 如果是首次调用查函数,进行f[x]赋值。 */
  10. f[x]=x;
  11. return f[x]==x?x:f[x]=findx(f[x]);
  12. }
  13. int main()
  14. {
  15. ios::sync_with_stdio(0),cin.tie(0);
  16. int i,j,p,x,y;
  17. cin>>n>>m>>q;/**< 本题目n很大,所以不能像往常那样循环对所有f[i]赋值。 */
  18. // for(i=1; i<=n; i++)
  19. // f[i]=i;
  20. for(i=1; i<=m; i++)/**< 把开始的关系set存起来 */
  21. {
  22. cin>>x>>y;
  23. if(x>y)/**< 处理下次序,这样避免重复存储,也方便查询 */
  24. swap(x,y);
  25. s.insert({x,y});
  26. }
  27. for(i=1; i<=q; i++)
  28. {
  29. cin>>p>>x>>y;
  30. if(x>y)/**< 同上 */
  31. swap(x,y);
  32. op[i][0]=p,op[i][1]=x,op[i][2]=y;
  33. if(op[i][0]==1)
  34. {
  35. if(s.count({x,y}))/**< 1是遗忘,此处在set集合中去掉这个关系 */
  36. s.erase({x,y});
  37. else
  38. op[i][0]=0;/**< 如果set没有这个关系,那么标记下这个关系无效,后续不会处理 */
  39. }
  40. }
  41. for(auto it=s.begin(); it!=s.end(); it++)/**< 将遗忘后所有关系并查集 */
  42. {
  43. int f1=findx(it->first),f2=findx(it->second);
  44. if(f1!=f2)
  45. f[f1]=f2;
  46. }
  47. vector<string>ans;/**< 逆序存储答案 */
  48. for(i=q; i>=1; i--)
  49. {
  50. if(op[i][0]==1) /**< 把第i个关系加回去,对于i-1之前的询问,这个关系是有效的 */
  51. {
  52. int f1=findx(op[i][1]),f2=findx(op[i][2]);
  53. if(f1!=f2)
  54. f[f1]=f2;
  55. }
  56. else if(op[i][0]==2)
  57. {
  58. int f1=findx(op[i][1]),f2=findx(op[i][2]);
  59. if(f1==f2)
  60. ans.push_back("Yes");
  61. else
  62. ans.push_back("No");
  63. }
  64. }
  65. for(i=ans.size()-1; i>=0; i--)
  66. cout<<ans[i]<<endl;
  67. return 0;
  68. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号