[关闭]
@Pinetrie 2019-10-20T07:53:22.000000Z 字数 8939 阅读 840

树链剖分 #### 标题

题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x

输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn = 100010;
  5. ll w[maxn],root;
  6. ll N,M,R,P;
  7. //线段树///////////////////////////////////////////////////////////////////
  8. ll A[maxn<<2],Sum[maxn<<2],Add[maxn<<2];
  9. void Pushup(ll rt)
  10. {
  11. Sum[rt] = (Sum[rt<<1] + Sum[rt<<1|1]) % P;
  12. }
  13. void Pushdown(ll rt,ll ln,ll rn)
  14. {
  15. if(Add[rt])
  16. {
  17. Add[rt<<1] = (Add[rt<<1] + Add[rt]) % P;
  18. Add[rt<<1|1] = (Add[rt<<1|1] + Add[rt]) % P;
  19. Sum[rt<<1] = (Sum[rt<<1] + ln * Add[rt]) % P;
  20. Sum[rt<<1|1] = (Sum[rt<<1|1] + rn * Add[rt]) % P;
  21. Add[rt] = 0;
  22. }
  23. }
  24. void build(ll l,ll r,ll rt)
  25. {
  26. if(l == r)
  27. {
  28. Sum[rt] = A[l];
  29. return;
  30. }
  31. ll m = (l + r)>>1;
  32. build(l,m,rt<<1);
  33. build(m + 1,r,rt<<1|1);
  34. Pushup(rt);
  35. }
  36. ll query(ll L,ll R,ll l,ll r,ll rt)
  37. {
  38. if(L <= l && R >= r)
  39. {
  40. return Sum[rt];
  41. }
  42. ll m = (l + r)>>1;
  43. Pushdown(rt,m - l + 1,r - m);
  44. ll Ans = 0;
  45. if(L <= m) Ans = (Ans + query(L,R,l,m,rt<<1)) % P;
  46. if(R > m) Ans = (Ans + query(L,R,m + 1,r,rt<<1|1)) % P;
  47. return Ans;
  48. }
  49. void update(ll L,ll R,ll C,ll l,ll r,ll rt)
  50. {
  51. if(L <= l && R >= r)
  52. {
  53. Sum[rt] = (Sum[rt] + (r - l + 1) * C) % P;
  54. Add[rt] = (Add[rt] + C) % P;
  55. return;
  56. }
  57. ll m = (l + r)>>1;
  58. Pushdown(rt,m - l + 1,r - m);
  59. if(L <= m) update(L,R,C,l,m,rt<<1);
  60. if(R > m) update(L,R,C,m + 1,r,rt<<1|1);
  61. Pushup(rt);
  62. }
  63. //////////////////////////////////////////////////////////
  64. 预处理///////////////////////////////////////////////////
  65. ll head[maxn],f[maxn],dep[maxn],siz[maxn],son[maxn],rk[maxn],top[maxn],id[maxn];
  66. ll tot,cnt;
  67. struct Edge
  68. {
  69. ll v,next;
  70. }e[maxn * 2];
  71. void addnode(ll u,ll v)
  72. {
  73. e[tot].v = v;
  74. e[tot].next = head[u];
  75. head[u] = tot++;
  76. }
  77. void dfs1(ll u,ll fa,ll deep)
  78. {
  79. f[u] = fa;
  80. dep[u] = deep;
  81. siz[u] = 1;
  82. for(ll i = head[u];i != -1;i = e[i].next)
  83. {
  84. ll v = e[i].v;
  85. if(v == fa) continue;
  86. dfs1(v,u,deep + 1);
  87. siz[u] += siz[v];
  88. if(siz[v] > siz[son[u]]) son[u] = v;
  89. }
  90. }
  91. void dfs2(ll u,ll t)
  92. {
  93. top[u] = t;
  94. id[u] = ++cnt;
  95. rk[cnt] = u;
  96. if(!son[u]) return;
  97. dfs2(son[u],t);
  98. for(ll i = head[u];i != -1;i = e[i].next)
  99. {
  100. ll v = e[i].v;
  101. if(v != son[u] && v != f[u]) dfs2(v,v);
  102. }
  103. }
  104. 询问//////////////////////////////////////////
  105. ll getsum(ll x,ll y)
  106. {
  107. ll ans = 0,fx = top[x],fy = top[y];
  108. while(fx != fy)
  109. {
  110. if(dep[fx] >= dep[fy])
  111. {
  112. ans = (ans + query(id[fx],id[x],1,N,1)) % P;
  113. x = f[fx],fx = top[x];
  114. }
  115. else
  116. {
  117. ans = (ans + query(id[fy],id[y],1,N,1)) % P;
  118. y = f[fy],fy = top[y];
  119. }
  120. }
  121. if(id[x] <= id[y]) ans = (ans + query(id[x],id[y],1,N,1)) % P;
  122. else ans = (ans + query(id[y],id[x],1,N,1)) % P;
  123. return ans;
  124. }
  125. void getupdate(ll x,ll y,ll C)
  126. {
  127. ll fx = top[x],fy = top[y];
  128. while(fx != fy)
  129. {
  130. if(dep[fx] >= dep[fy])
  131. {
  132. update(id[fx],id[x],C,1,N,1);
  133. x = f[fx],fx = top[x];
  134. }
  135. else
  136. {
  137. update(id[fy],id[y],C,1,N,1);
  138. y = f[fy],fy = top[y];
  139. }
  140. }
  141. if(id[x] <= id[y]) update(id[x],id[y],C,1,N,1);
  142. else update(id[y],id[x],C,1,N,1);
  143. }
  144. ll getsonsum(ll x)
  145. {
  146. return query(id[x],id[x] + siz[x] - 1,1,N,1);
  147. }
  148. void getsonupdate(ll x,ll z)
  149. {
  150. update(id[x],id[x] + siz[x] - 1,z,1,N,1);
  151. }
  152. int main()
  153. {
  154. memset(head,-1,sizeof(head));
  155. scanf("%lld %lld %lld %lld",&N,&M,&R,&P);
  156. for(ll i = 1;i <= N;i++) scanf("%lld",&w[i]);
  157. for(ll i = 1;i < N;i++)
  158. {
  159. ll u,v;
  160. scanf("%lld %lld",&u,&v);
  161. addnode(u,v);
  162. addnode(v,u);
  163. }
  164. dfs1(R,0,1);
  165. dfs2(R,R);
  166. for(ll i = 1;i <= N;i++)
  167. {
  168. A[i] = w[rk[i]];
  169. }
  170. build(1,N,1);
  171. while(M--)
  172. {
  173. ll op,x,y,z;
  174. scanf("%lld",&op);
  175. if(op == 1)
  176. {
  177. scanf("%lld %lld %lld",&x,&y,&z);
  178. getupdate(x,y,z);
  179. }
  180. if(op == 2)
  181. {
  182. scanf("%lld %lld",&x,&y);
  183. printf("%lld\n",getsum(x,y));
  184. }
  185. if(op == 3)
  186. {
  187. scanf("%lld %lld",&x,&z);
  188. getsonupdate(x,z);
  189. }
  190. if(op == 4)
  191. {
  192. scanf("%lld",&x);
  193. printf("%lld\n",getsonsum(x));
  194. }
  195. }
  196. return 0;
  197. }

主席树(区间第K大)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 100010;
  4. int T,n,m,np;
  5. int L[maxn*20],R[maxn*20],Sum[maxn*20],A[maxn],B[maxn],Root[maxn];
  6. int build(int l,int r)
  7. {
  8. int rt = ++np;
  9. Sum[rt] = 0;
  10. if(l < r)
  11. {
  12. int mid = (l + r) / 2;
  13. L[rt] = build(l,mid);
  14. R[rt] = build(mid + 1,r);
  15. }
  16. return rt;
  17. }
  18. int update(int pre,int l,int r,int x)
  19. {
  20. int rt = ++np;
  21. L[rt] = L[pre],R[rt] = R[pre],Sum[rt] = Sum[pre] + 1;
  22. int mid = (l + r) / 2;
  23. if(l < r)
  24. {
  25. if(x <= mid) L[rt] = update(L[pre],l,mid,x);
  26. else R[rt] = update(R[pre],mid + 1,r,x);
  27. }
  28. return rt;
  29. }
  30. int query(int u,int v,int l,int r,int k)
  31. {
  32. if(l >= r) return l;
  33. int mid = (l + r) / 2;
  34. int x = Sum[L[v]] - Sum[L[u]];
  35. if(x >= k) return query(L[u],L[v],l,mid,k);
  36. else return query(R[u],R[v],mid + 1,r,k - x);
  37. }
  38. int main()
  39. {
  40. int T;
  41. scanf("%d",&T);
  42. while(T--)
  43. {
  44. np = 0;
  45. scanf("%d %d",&n,&m);
  46. for(int i = 1;i <= n;i++)
  47. {
  48. scanf("%d",&A[i]);
  49. B[i] = A[i];
  50. }
  51. sort(B + 1,B + 1 + n);
  52. int len = unique(B + 1,B + 1 + n) - (B + 1);
  53. Root[0] = build(1,len);
  54. for(int i = 1;i <= n;i++)
  55. {
  56. int p = lower_bound(B + 1,B + 1 + len,A[i]) - B;
  57. Root[i] = update(Root[i - 1],1,len,p);
  58. }
  59. while(m--)
  60. {
  61. int x,y,z;
  62. scanf("%d %d %d",&x,&y,&z);
  63. int p = query(Root[x - 1],Root[y],1,len,z);
  64. printf("%d\n",B[p]);
  65. }
  66. }
  67. return 0;
  68. }

线性基

线性基的性质:
1、原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
2、线性基里面的任意一些数异或起来都不能得到0。
3、线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的。

  1. struct LineBase
  2. {
  3. ll b[66];//上三角矩阵
  4. ll p[66];//对角矩阵
  5. int cnt;
  6. int max_b = 63;
  7. void init()
  8. {
  9. memset(b,0,sizeof(b));
  10. memset(p,0,sizeof(p));
  11. cnt = 0;
  12. }
  13. bool Insert(ll x)//插入
  14. {
  15. for(int i = max_b;i >= 0;i--)
  16. {
  17. if((x>>i)&1)
  18. {
  19. if(b[i] == 0)
  20. {
  21. b[i] = x;
  22. break;
  23. }
  24. x = x^b[i];
  25. }
  26. }
  27. if(x > 0) cnt++;
  28. return (x > 0);
  29. }
  30. LineBase Merge(LineBase n1,LineBase n2)//线性基合并
  31. {
  32. LineBase ret = n1;
  33. for(int i = 0;i <= max_b;i++)
  34. {
  35. if(n2.b[i]) ret.Insert(n2.b[i]);
  36. }
  37. return ret;
  38. }
  39. LineBase Merge2(LineBase A,LineBase B)//线性基求交
  40. {
  41. LineBase All,C,D;
  42. All.init();
  43. C.init();
  44. D.init();
  45. for(ll i = 60;i >= 0;i--)
  46. {
  47. All.b[i] = A.b[i];
  48. D.b[i] = 1ll<<i;
  49. }
  50. for(ll i = 60;i >= 0;i--)
  51. {
  52. if(B.b[i])
  53. {
  54. ll v = B.b[i],k = 0;
  55. bool can = true;
  56. for(ll j = 60;j >= 0;j--)
  57. {
  58. if(v & (1ll<<j))
  59. {
  60. if(All.b[j])
  61. {
  62. v^=All.b[j];
  63. k^=D.b[j];
  64. }
  65. else
  66. {
  67. can = false;
  68. All.b[j] = v;
  69. D.b[j] = k;
  70. break;
  71. }
  72. }
  73. }
  74. if(can)
  75. {
  76. ll v = 0;
  77. for(ll j = 60;j >= 0;j--)
  78. {
  79. if(k & (1ll<<j))
  80. {
  81. v^=A.b[j];
  82. }
  83. }
  84. C.Insert(v);
  85. }
  86. }
  87. }
  88. return C;
  89. }
  90. ll queryMax(ll x)//求最大
  91. {
  92. ll ans = x;
  93. for(int i = max_b;i >= 0;i--)
  94. {
  95. if((ans^b[i]) > ans) ans^=b[i];
  96. }
  97. return ans;
  98. }
  99. ll queryMin()//求最小
  100. {
  101. for(int i = 0;i < max_b;i++)
  102. {
  103. if(b[i]) return b[i];
  104. }
  105. return 0;
  106. }
  107. void rebuild()//化为对角矩阵
  108. {
  109. for(int i = max_b;i >= 0;i--)
  110. {
  111. for(int j = i - 1;j >= 0;j--)
  112. {
  113. if(b[i]&(1ll<<j)) b[i]^=b[j];
  114. }
  115. }
  116. cnt = 0;
  117. for(int i = 0;i <= max_b;i++)
  118. {
  119. if(b[i]) p[cnt++] = b[i];
  120. }
  121. }
  122. ll kthquery(ll k)//求第k大(必须先化为对角矩阵)
  123. {
  124. ll ans = 0;
  125. if(k >= (1ll<<cnt)) return -1;
  126. for(int i = max_b;i >= 0;i--)
  127. {
  128. if(k&(1ll<<i)) ans^=p[i];
  129. }
  130. return ans;
  131. }
  132. };

杜教BM

输入前几项数据,快速求解线性递推式的第n项。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. namespace linear_seq
  4. {
  5. #define rep(i,a,n) for(int i = a;i < n;i++)
  6. #define per(i,a,n) for(int i = n - 1;i >= a;i--)
  7. #define pb push_back
  8. #define mp make_pari
  9. #define all(x) (x).begin(),(x).end()
  10. #define fi first
  11. #define se second
  12. #define SZ(x) ((int)(x).size())
  13. typedef vector<int> VI;
  14. typedef pair<int,int> PII;
  15. typedef long long ll;
  16. const ll mod = 1e9 + 7;
  17. const int N = 100010;
  18. ll res[N],base[N],_c[N],_md[N];
  19. ll modpow(ll a,ll b,ll mod) {ll res = 1;a %= mod;for(;b;b>>=1){if(b&1)res = res*a%mod;a=a*a%mod;}return res;}
  20. vector<int> Md;
  21. void mul(ll *a,ll *b,ll k)
  22. {
  23. rep(i,0,k+k) _c[i] = 0;
  24. rep(i,0,k) if(a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
  25. for(int i = k+k-1;i>=k;i--) if(_c[i])
  26. rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
  27. rep(i,0,k) a[i]=_c[i];
  28. }
  29. int solve(ll n,VI a,VI b)
  30. {
  31. ll ans=0,pnt=0;
  32. int k=SZ(a);
  33. rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
  34. Md.clear();
  35. rep(i,0,k) if(_md[i]!=0) Md.push_back(i);
  36. rep(i,0,k) res[i]=base[i]=0;
  37. res[0]=1;
  38. while((1ll<<pnt)<=n) pnt++;
  39. for(int p=pnt;p>=0;p--)
  40. {
  41. mul(res,res,k);
  42. if((n>>p)&1)
  43. {
  44. for(int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
  45. rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
  46. }
  47. }
  48. rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
  49. if(ans<0) ans+=mod;
  50. return ans;
  51. }
  52. VI BM(VI s)
  53. {
  54. VI C(1,1),B(1,1);
  55. int L=0,m=1,b=1;
  56. rep(n,0,SZ(s))
  57. {
  58. ll d=0;
  59. rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
  60. if(d==0) ++m;
  61. else if(2*L<=n)
  62. {
  63. VI T=C;
  64. ll c=mod-d*modpow(b,mod-2,mod)%mod;
  65. while(SZ(C)<SZ(B)+m) C.pb(0);
  66. rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
  67. L=n+1-L;B=T;b=d;m=1;
  68. }
  69. else
  70. {
  71. ll c=mod-d*modpow(b,mod-2,mod)%mod;
  72. while(SZ(C)<SZ(B)+m) C.pb(0);
  73. rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
  74. ++m;
  75. }
  76. }
  77. return C;
  78. }
  79. int gao(VI a,ll n)
  80. {
  81. VI c=BM(a);
  82. c.erase(c.begin());
  83. rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
  84. return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
  85. }
  86. }
  87. typedef long long ll;
  88. const int MOD = 1e9 + 7;
  89. ll n,k;
  90. ll dp[2050];
  91. ll powMod(ll a,ll b)
  92. {
  93. ll res = 1;
  94. while(b)
  95. {
  96. if(b % 2 == 1) res = res * a % MOD;
  97. a = a * a % MOD;
  98. b /= 2;
  99. }
  100. return res;
  101. }
  102. int main()
  103. {
  104. int T;
  105. scanf("%d",&T);
  106. while(T--)
  107. {
  108. scanf("%lld %lld",&k,&n);
  109. if(n == -1)
  110. {
  111. ll ans = 2;
  112. ans = ans * powMod(k + 1,MOD - 2) % MOD;
  113. printf("%lld\n",ans);
  114. continue;
  115. }
  116. ll p = powMod(k,MOD - 2);
  117. //把递推式的前2 * k项计算出来并放入vetor中
  118. vector<int>v;
  119. v.push_back(1);
  120. dp[0] = 1;
  121. for(int i = 1;i <= 2 * k;i++)
  122. {
  123. dp[i] = 0;
  124. for(int j = i - 1;j >= max(0ll,i - k);j--)
  125. {
  126. dp[i] = (dp[i] + dp[j] * p % MOD) % MOD;
  127. }
  128. v.push_back(dp[i]);
  129. }
  130. //调用函数计算得到第n项的值
  131. ll ans = linear_seq::gao(v,n);
  132. printf("%lld\n",ans);
  133. }
  134. return 0;
  135. }

解线性同余方程

ans * ans =(同余) n % p

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. ll w;
  5. ll p;
  6. bool ok;
  7. ll powMod(ll a,ll b)
  8. {
  9. ll res = 1;
  10. while(b)
  11. {
  12. if(b&1) res = res * a % p;
  13. a = a * a % p;
  14. b /= 2;
  15. }
  16. return res;
  17. }
  18. struct QuadraticField
  19. {
  20. ll x,y;
  21. QuadraticField operator*(QuadraticField T)
  22. {
  23. QuadraticField ans;
  24. ans.x = (this->x * T.x % p + this->y * T.y % p * w % p) % p;
  25. ans.y = (this->x * T.y % p + this->y * T.x % p) % p;
  26. return ans;
  27. }
  28. QuadraticField operator^(ll b)
  29. {
  30. QuadraticField ans;
  31. QuadraticField a = *this;
  32. ans.x = 1;
  33. ans.y = 0;
  34. while(b)
  35. {
  36. if(b & 1)
  37. {
  38. ans = ans * a;
  39. b--;
  40. }
  41. b /= 2;
  42. a = a * a;
  43. }
  44. return ans;
  45. }
  46. };
  47. ll Lengender(ll a)
  48. {
  49. ll ans = powMod(a,(p - 1) / 2);
  50. if(ans + 1 == p) return -1;
  51. else return ans;
  52. }
  53. ll GetW(ll n,ll a)
  54. {
  55. return ((a * a - n) % p + p) % p;
  56. }
  57. ll Solve(ll n)
  58. {
  59. ll a;
  60. if(p == 2) return n;
  61. if(Lengender(n) == -1) ok = false;
  62. srand((unsigned)time(NULL));
  63. while(1)
  64. {
  65. a = rand() % p;
  66. w = GetW(n,a);
  67. if(Lengender(w) == -1) break;
  68. }
  69. QuadraticField ans,res;
  70. res.x = a;
  71. res.y = 1;
  72. ans = res ^ ((p + 1) / 2);
  73. return ans.x;
  74. }
  75. int main()
  76. {
  77. ll n,ans1,ans2;
  78. while(scanf("%lld %lld",&n,&p) != EOF)
  79. {
  80. ok = true;
  81. n %= p;
  82. ans1 = Solve(n);
  83. ans2 = p - ans1;
  84. if(!ok) printf("-1\n");
  85. else printf("%lld %lld\n",ans1,ans2);
  86. }
  87. return 0;
  88. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注