当前位置:   article > 正文

小沙的算数--并查集 (联通块)_小沙的算术

小沙的算术

题目

小沙不会计数,所以他想从小学数学开始学起,今天老师布置了一大堆算数题,但爱耍小聪明的小沙发现这么多的算数题中,他们中间的符号都是+++或者×\times× 并且每个题+++和×\times×的位置都是一样的

小沙想要快点去玩耍,所以求助好哥哥你帮帮他快速的计算出答案。

由于答案数字过大 所以我们对100000000710000000071000000007取模

输入描述:

第一行 给定二个个数n代表有n个数进行计算 q代表有q次询问
(2≤n≤1062\leq n \leq 10^62≤n≤106,1≤q≤1051\leq q \leq 10^51≤q≤105) 第二行 给定一个一个长度为n-1的*+字符串 表示我们要进行的计算符号是什么 第三行 给定n个整数,代表这每个位置上的数字
随后q行每行两个数字x,y代表着将第x个数字改成y且x≤nx\leq nx≤n
本题所有数均为正整数,且小于100000000710000000071000000007
但并不保证计算过程中是否会出现大于100000000710000000071000000007的值

输出描述:

对于每次查询,回答出整个算式的答案 每个答案占一行

(本题中的每次查询均不独立,也就是说每次查询修改之后的数,都会永远的修改)

样例输入

5 3
++*+
1 1 3 1 1
4 2
1 7
5 6

样例输出

9
15
20

分析

观察可以发现,用乘号连在一起的数不受加号影响,那将乘号连起来的结点合并,将所有数相乘的结果存储在父结点。

用mu[i]表示以i作为父结点时该联通块相乘的结果,如果没有乘号连接,则mu[i]就等于a[i]的值。

当改变数时,对应的连通块值会改变,那就将所有结果先算出来放在sum里,最后再改变sum的值。因为计算过程中顺便取了模,所以要将mu[i]和a[i]放大后再运算,再缩小与sum相加。

除以用乘法逆元,结果+mod%mod保证为正数。

式子mu[xx]*qmi(a[x],mod-2,mod)是乘法逆元和放大操作,作用就是联通块的值除去a[x]

放大操作用快速幂进行快速放大

c*((mu[xx]*qmi(a[x],mod-2,mod))%mod)%mod

=y*((mu[xx]*qmi(a[x],mod-2,mod))%mod)%mod-a[x]*((mu[xx]*qmi(a[x],mod-2,mod))%mod)%mod

如果是有乘号的联通块,

就是sum加上(联通块除去被替换的数再乘上新的数),减去(之前联通块的值)

如果是没有乘号的联通块,mu[xx]*qmi(a[x],mod-2,mod)的值为1

c*((mu[xx]*qmi(a[x],mod-2,mod))%mod)%mod=y-a[x]

代码

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<cstring>
  4. #define ll long long
  5. using namespace std;
  6. const int mod = 1000000007;
  7. ll fa[2000015];
  8. ll mu[2000015];
  9. ll a[2000015];
  10. ll n,m,sum;
  11. ll has[2000015];
  12. string s;
  13. ll find(ll x)
  14. {
  15. return x==fa[x]?x:fa[x] = find(fa[x]);
  16. }
  17. void mul(ll x,ll y)//乘
  18. {
  19. mu[find(x)] = (mu[find(x)]*mu[find(y)])%mod;
  20. mu[find(x)]%=mod;
  21. fa[find(y)] = find(x);
  22. }
  23. ll qmi(ll a, ll b, ll p)//快速幂
  24. {
  25. ll res = 1 % p;
  26. a %= p;
  27. while (b > 0)
  28. {
  29. if(b & 1)
  30. res = res * a % p;
  31. a = a * a % p;
  32. b >>= 1;
  33. }
  34. return res;
  35. }
  36. int main(){
  37. cin>>n>>m;
  38. for(int i = 1;i<=n+10;++i)
  39. fa[i] = i;
  40. cin>>s;
  41. for(int i = 1;i<=n;++i)
  42. {
  43. cin>>a[i];
  44. a[i]%=mod;
  45. mu[i] = a[i];
  46. if(i>1&&s[i-2]=='*')
  47. mul(i,i-1);
  48. }
  49. for(int i = 1;i<=n;++i)
  50. {
  51. if(!has[find(i)])
  52. {
  53. sum = (sum+mu[find(i)])%mod;
  54. has[find(i)] = 1;
  55. }
  56. }
  57. for(int i = 1;i<=m;++i)
  58. {
  59. ll x,y;
  60. cin>>x>>y;
  61. ll c = y-a[x];
  62. ll xx = find(x);
  63. //下面这条式子乘和加都适合
  64. sum = (sum+mod+(c*((mu[xx]*qmi(a[x],mod-2,mod))%mod)%mod)%mod)%mod;//修改总和
  65. cout<<sum%mod<<endl;
  66. mu[xx] = (mu[xx]*qmi(a[x],mod-2,mod)%mod)*y%mod;//换联通块的值
  67. a[x] = y%mod;//换原数组的值
  68. }
  69. return 0;
  70. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/800431
推荐阅读
相关标签
  

闽ICP备14008679号