維護子樹的全部子樹的權值和時,需要用到樹的DFS序列,樹的每個子樹都對應DFS序列中的連續一段
黃金樹影
題意:給定一棵樹及每個節點的權值,給定一組操作,輸入 1 a x ,表示節點a權值加上x;輸入 2 a ,表示詢問節點a的子樹權值和(包含a)。
考慮到樹的DFS序列,則問題轉變為對某個序列維護區間和以及單點修改,這裡透過樹狀陣列來維護。
程式碼
#include <bits/stdc++.h>
#define int long long
#define MOD 998244353
using namespace std;
int a[500005]={0};
int t[500005]={0};
int p[500005]={0};
int b[500005]={0};
int c[500005]={0};
int tms=1,n;
vector<int>g[500005];
vector<int>vis(500005,0);
int lowbit(int x){
return x&-x;
}
int getsum(int x) {
int ans = 0;
while (x > 0) {
ans = ans + c[x];
x = x - lowbit(x);
}
return ans;
}
void add(int x, int k) {
while (x <= n) {
c[x] = c[x] + k;
x = x + lowbit(x);
}
}
void dfs(int x){
vis[x]=1;
t[tms]=x;
p[x]=tms;
tms++;
for(int i=0;i<g[x].size();i++){
if(!vis[g[x][i]]){
dfs(g[x][i]);
vis[g[x][i]]=0;
}
}
b[x]=tms-1;
}
int32_t main() {
int T = 1;
//cin >> T;
while (T--) {
int m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=2;i<=n;i++){
int u;
cin>>u;
g[i].emplace_back(u);
g[u].emplace_back(i);
}
dfs(1);
for(int i=1;i<=n;i++){
add(i,a[t[i]]);
}
for(int i=0;i<m;i++){
int x,y;
cin>>x>>y;
if(x==1){
int k;
cin>>k;
add(p[y],k);
}else{
cout<<getsum(b[y])-getsum(p[y]-1)<<endl;
}
}
}
}
當題目中出現n過大的情況且涉及位運算時,可以考慮逐位處理。
xor^2
題意:求\(\displaystyle\sum_{i=1}^n\displaystyle\sum_{j=1}^n(i xor j)\),\((1\leq n\leq 10^{18})\)
逐位考慮,若第i位出現1的個數為\(a[i]\),則第i位對答案的貢獻為\(a[i]*(n-a[i])*2*2^i\),注意不要超過資料範圍即可。
#include <bits/stdc++.h>
#define int long long
#define MOD 998244353
using namespace std;
int32_t main() {
int T = 1;
cin >> T;
while (T--) {
int a[10086];
int n,s=0;
cin >> n;
int x=0,p=n;
while(p){
a[x]=p%2;
x++;
p>>=1;
}
for(int i=0;i<x;i++){
a[i]=n/(1ll<<(i+1))*((1ll<<(i)));
if(n%(1ll<<(i+1))>=(1ll<<(i))){
a[i]+=n%(1ll<<(i))+1;
}
s+=a[i]%MOD*(((n-a[i]))%MOD)%MOD*2%MOD*((1ll<<(i))%MOD)%MOD;
s%=MOD;
}
cout<<s<<endl;
}
}
對於質因數分解相關的問題,可以只列舉\(\sqrt{n}\)範圍內的素數來減小時間複雜度,也可透過篩法來求素數再次減小時間複雜度
求除數
題意:給定n,求n的因數的個數\((1\leq n\leq 10^8)\)
有多組資料,所以先計算\((1, 10^4)\)範圍內素數,可透過尤拉篩來求,再對每個n列舉素數分解質因數,最後輸出即可。
#include <bits/stdc++.h>
#define int long long
#define MOD 1000000007
using namespace std;
int pos=0;
vector<int> q(10005),p(10005,1);
void prime(int x){
p[0]=0,p[1]=0;
for(int i=2;i<=x;i++){
if(p[i]){
q[pos]=i;
pos++;
}
for(int j=0;j<pos;j++){
if(i*q[j]>x)break;
p[i*q[j]]=0;
if(i%q[j]==0)break;
}
}
}
int32_t main() {
int T = 1;
cin >> T;
prime(1e4);
while (T--) {
int n,s=1;
cin>>n;
for(int i=0;i<pos;i++){
int x=0;
while(n%q[i]==0){
n/=q[i];
x++;
}
s*=(x+1);
if(n==1)break;
}
if(n>1){
s*=2;
}
cout<<s<<endl;
}
}