• 并查集——奇偶游戏(带边权和扩展域做法)


    传送门:239. 奇偶游戏 - AcWing题库

    思路:

    第一种是用带边权的方法来解

    首先对于题目中的序列,我们用一个前缀和数组sum[i]来表示1~i中所有数的奇数的个数。

    可以发现假如题目给的一个范围[l,r]里面有偶数个1,等价于sum[l-1]与sum[r]的奇偶性相同,

    证明:s[l,r]里面的奇偶性可以由sum[r]-sum[l-1]得到,s[l,r]有偶数个1,说明sum[r]-sum[l-1]要么是两个偶数,要么是两个奇数。否则得不出s[l,r]里面是有偶数个1这个结论。

    [l,r]里面有奇数个1的情况下说明,sum[l-1]与sum[r]的奇偶性不同。证明和上面类似,此处略。

    这道题目里面要传递的关系不止一种,

    1.x1与x2的奇偶性相同+x2与x3的奇偶性相同可以得到x1和x3的奇偶性相同

    2.x1与x2的奇偶性相同+x2与x3的奇偶性不同可以得到x1和x3的奇偶性不同

    3.x1与x2的奇偶性不同+x2与x3的奇偶性不同可以得到x1和x3的奇偶性相同

    步骤

    0.首先注意到题目s的序列长度很大,但回答的次数却很小,所以这里要先离散化一下,

    1.用一个并查集树来表示一个集合,d[i]表示当前节点跟f[x]节点的奇偶性关系,0表示相同,1表示不同。在路径压缩的同时对x到根节点路径上的所有边权做异或运算便可得到x和根节点的关系。

    同时,如果想获得同一棵树里面的两个不同节点的奇偶性关系就是直接d[x]^d[y],这里就使用到了上面所说的关系传递。

    2.对于每一个回答,都要先判断x,y是否属于同一集合,如果是的话就用d[x]^d[y]去对比回答里面的关系是否相同。

       如果x,y不属于同一集合,就要合并两个集合,得到两个集合的根节点pa,pb后,令pa为pb的子节     点。有ans=d[x]^d[y]^d[pa]可以得到d[pa]=ans^d[x]^d[y];

    代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef long long ll;
    7. const int N=3e4+10;
    8. struct nod
    9. {
    10. int l,r, ans;
    11. }node[N];
    12. int a[N],f[N],d[N];
    13. int n,m,t;
    14. void getdata()
    15. {
    16. cin>>n>>m;
    17. for(int i=1;i<=m;i++)
    18. {
    19. char str[5];
    20. scanf("%d%d%s",&node[i].l,&node[i].r,str);
    21. if(str[0]=='o') node[i].ans=1;
    22. else node[i].ans=0;
    23. a[++t]=node[i].l-1;
    24. a[++t]=node[i].r;
    25. }
    26. sort(a+1,a+t+1);
    27. n=unique(a+1,a+t+1)-a-1;
    28. }
    29. int get(int x)
    30. {
    31. if(x==f[x]) return x;
    32. int u=get(f[x]);
    33. d[x]^=d[f[x]];
    34. return f[x]=u;
    35. }
    36. int main()
    37. {
    38. getdata();
    39. for(int i=1;i<=n;i++) f[i]=i;
    40. for(int i=1;i<=m;i++)
    41. {
    42. int x=lower_bound(a+1,a+n+1,node[i].l-1) -a;
    43. int y=lower_bound(a+1,a+n+1,node[i].r) -a;
    44. int pa=get(x),pb=get(y);
    45. if(pa==pb)
    46. {
    47. if((d[x]^d[y])!=node[i].ans)
    48. {
    49. cout<-1<
    50. return 0;
    51. }
    52. }else
    53. {
    54. f[pa]=pb;
    55. d[pa]=d[x]^d[y]^node[i].ans;
    56. }
    57. }
    58. cout<
    59. return 0;
    60. }

    扩展域:

    思路:

    待写

    代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef long long ll;
    7. const int N=3e4+10;
    8. struct nod
    9. {
    10. int l,r, ans;
    11. }node[N];
    12. int a[N],f[N],d[N];
    13. int n,m,t;
    14. void getdata()
    15. {
    16. cin>>n>>m;
    17. for(int i=1;i<=m;i++)
    18. {
    19. char str[5];
    20. scanf("%d%d%s",&node[i].l,&node[i].r,str);
    21. if(str[0]=='o') node[i].ans=1;
    22. else node[i].ans=0;
    23. a[++t]=node[i].l-1;
    24. a[++t]=node[i].r;
    25. }
    26. sort(a+1,a+t+1);
    27. n=unique(a+1,a+t+1)-a-1;
    28. }
    29. int get(int x)
    30. {
    31. if(x==f[x])
    32. return x;
    33. return f[x]=get(f[x]);
    34. }
    35. int main()
    36. {
    37. getdata();
    38. for(int i=1;i<=2*n;i++)
    39. f[i]=i;
    40. for(int i=1;i<=m;i++)
    41. {
    42. int x= lower_bound(a+1,a+n+1,node[i].l-1) -a;
    43. int y=lower_bound(a+1,a+n+1,node[i].r) -a;
    44. int x_odd=x,x_even=x+n;
    45. int y_odd=y,y_even=y+n;
    46. if(node[i].ans==0)
    47. {
    48. if(get(x_odd)==get(y_even))
    49. {
    50. cout<-1<
    51. return 0;
    52. }
    53. f[get(x_odd)]=get(y_odd);
    54. f[get(x_even)]=get(y_even);
    55. }else
    56. {
    57. if(get(x_odd)==get(y_odd))
    58. {
    59. cout<-1<
    60. return 0;
    61. }
    62. f[get(x_odd)]=get(y_even);
    63. f[get(x_even)]=get(y_odd);
    64. }
    65. }
    66. cout<
    67. return 0;
    68. }

  • 相关阅读:
    2021年暨南大学计算机848真题
    温度敏感/PH敏感/电场敏感/温度/pH双重敏感/磁场敏感型水凝胶的制备
    VSCode学习笔记一:添加代码模板
    P1008 [NOIP1998 普及组] 三连击
    nonebot 原神角色查询插件
    VSCode_快捷键
    android 动画中插值器Interpolator详解
    emqx broker安装
    一段惊呆下巴的 JavaScript 代码
    Springboot物资发放管理系统
  • 原文地址:https://blog.csdn.net/m0_62327332/article/details/126859401