• AcWing 246. 区间最大公约数----线段树 + 差分模板题


    debug1个多小时.......

    线段树 + 差分模板题
    差分模板可以参考 AcWing 797. 差分

    线段树的详细模板可以参考 AcWing 1275. 最大数

    思路

    第一个操作:

            因为涉及到了区间修改的问题,直观上需要pushdown操作,即用父节点信息来更新子节点信息,但是pushdown操作很复杂并且容易写错,所以使用差分数组的技巧:

                    设原数组第i为的值为a[i],差分数组b:b[i]=a[i]-a[i-1]

    第二个操作:

            根据"更相减损术"

            则有gcd(a,b)=gcd(a,b-a)

            推广得到:

            gcd(a,b,c)=((a,b),(b,c))=(a,b-a,c-b)

            那么我们发现了一个规律:

            (a[l],.......a[r])这个区间的最大公约是为

              (a[l],a[l+1]-a[l]....a[r]-a[r-1])

            可以得到(a[l],b[l+1].......b[r])

            那么问题转化为差分数组b[l+1],b[r]这个区间的最大公约数与a[l]的最大公约数

            (因为线段树维护的是b数组,b[l+1]~b[r]这个区间的最大公约数query一下就行了)

    1. #include<bits/stdc++.h>
    2. #define int long long
    3. using namespace std;
    4. const int N=5e5+10;
    5. int n,m;
    6. int w[N];
    7. struct node {
    8. int l,r,sum,d;
    9. } t[N*4];
    10. int gcd(int a,int b) {
    11. return b ? gcd(b,a % b) : a;
    12. }
    13. void pushup(node &u,node &left,node &right) {
    14. u.sum = left.sum + right.sum;
    15. //cout<<u.l<<" "<<u.r<<" "<<u.sum<<endl;
    16. u.d = gcd(left.d,right.d);
    17. }
    18. void pushup(int u) { //重载一下pushup,可以省去一点步骤
    19. pushup(t[u],t[u << 1],t[u << 1 | 1]);
    20. }
    21. void build(int u,int l,int r) { //维护的是一个差分数组
    22. if(l == r) {
    23. int d = w[r] - w[r - 1];
    24. t[u] = {l,r,d,d};;
    25. } else {
    26. t[u].r = r, t[u].l = l;
    27. int mid = l + r >> 1;
    28. build(u << 1,l,mid);
    29. build(u << 1 | 1,mid + 1,r);
    30. pushup(u);
    31. }
    32. }
    33. void modify(int u,int x,int v) {
    34. if(t[u].l==x&&t[u].r==x) {
    35. int b=t[u].sum+v;
    36. t[u]= {x,x,b,b};
    37. } else {
    38. int mid=t[u].l+t[u].r>>1;
    39. if(x<=mid) {
    40. modify(u<<1,x,v);
    41. } else {
    42. modify(u<<1|1,x,v);
    43. }
    44. pushup(u);
    45. }
    46. }
    47. node query(int u,int l,int r) {
    48. if(t[u].l>=l&&t[u].r<=r)
    49. return t[u];
    50. else {
    51. int mid=t[u].l+t[u].r>>1;
    52. if(r<=mid) {
    53. return query(u<<1,l,r);
    54. } else if(l>mid) {
    55. return query(u<<1|1,l,r);
    56. } else {
    57. node res;
    58. auto left =query(u<<1,l,r);
    59. auto right=query(u<<1|1,l,r);
    60. pushup(res,left,right);
    61. return res;
    62. }
    63. }
    64. }
    65. signed main() {
    66. cin>>n>>m;
    67. for(int i=1; i<=n; i++) {
    68. cin>>w[i];
    69. }
    70. build(1,1,n);
    71. int l,r;
    72. char op[2];
    73. while(m--) {
    74. scanf("%s%lld%lld",op,&l,&r);
    75. if(*op=='C') {
    76. int d;
    77. cin>>d;
    78. modify(1,l,d);
    79. if (r + 1 <= n)
    80. modify(1,r + 1,-d);
    81. } else {
    82. node left=query(1,1,l);
    83. node right({0,0,0,0});
    84. if(l+1<=r) {
    85. right=query(1,l+1,r);
    86. //b[l + 1 ~ r]的最大公约数,
    87. //就相当于(A[l+1]-A[l] ,
    88. //A[l+2]-A[l+1] , A[l+3]-A[l+2] ,
    89. //... , A[r]-A[r-1])的最大公约数
    90. }
    91. //cout<<left.sum<<' '<<right.d<<endl;
    92. int res = abs(gcd(left.sum,right.d)); //约定最大公约数是没有负数的,所以遇到附属就把他取反
    93. printf("%lld\n",res);
    94. }
    95. }
    96. return 0;
    97. }
    98. /*

  • 相关阅读:
    chatgpt赋能python:Python请求头——让你的网络请求更有效率
    FNPLicensingService.exe 总提示要联网
    AWVS的使用
    使C#语言编程更加高效的伎俩
    密码学基础
    Java 关键字:synchronized详解
    vue3+ts做echarts做一个简单的折线渐变图
    V853 替换开机启动LOGO
    扩容磁盘的inode数量
    一文详细拆解Agent工作原理
  • 原文地址:https://blog.csdn.net/qq_64214980/article/details/127779885