SMU Winter 2024 div2 ptlks的周报Week 5(3.4-3.10)
维护子树的全部子树的权值和时,需要用到树的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;
}
}