题目链接
D-树上求和
做法:经典的题了,跑一个dfs序,然后用线段树维护即可,至于如何维护区间平方和。
若之前已经维护好了s 为某个区间的平方和,sum为区间和。
新加一个数x:
假设区间 [1,3] 有 a1 a2 a3
加入x
拆开:
=>
=>
所以区间维护s 和 sum 即可
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb emplace_back
#define pii pair<int,int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const ll mod = 23333;
const int N = 1e5 + 10;
vector<int> G[N];
int n, m, dfn[N], cnt, sz[N];
ll sum[4 * N], s[4 * N], lazy[4 * N], a[N], ran[N];
void dfs(int u,int fa)
{
dfn[u] = ++cnt;
ran[cnt] = u;
sz[u] = 1;
for(int v:G[u]){
if(v == fa) continue;
dfs(v, u);
sz[u] += sz[v];
}
}
void add(ll &x, ll y)
{
x=(x + y) % mod;
}
void pushdown(int id,int l,int r)
{
if(lazy[id]){
int mid = l + r>>1;
add(lazy[id<<1], lazy[id]);
add(lazy[id<<1|1], lazy[id]);
add(s[id<<1], lazy[id]*lazy[id]%mod*(mid-l+1)%mod+2ll*sum[id<<1]%mod*lazy[id]%mod);
add(s[id<<1|1], lazy[id]*lazy[id]%mod*(r-mid)%mod+2ll*sum[id<<1|1]%mod*lazy[id]%mod);
add(sum[id<<1], lazy[id]*(mid-l+1)%mod);
add(sum[id<<1|1], lazy[id]*(r-mid)%mod);
lazy[id]=0;
}
}
void pushup(int id)
{
sum[id]=(sum[id<<1]+sum[id<<1|1])%mod;
s[id]=(s[id<<1]+s[id<<1|1])%mod;
}
void up(int id,int l,int r,int ql,int qr,ll val)
{
if(ql<=l&&r<=qr){
add(lazy[id], val);
add(s[id], val*val%mod*(r-l+1)%mod+sum[id]*val%mod*2%mod);
add(sum[id], val*(r-l+1)%mod);
return ;
}
pushdown(id, l, r);
int mid = l + r>>1;
if(ql <= mid) up(id<<1, l, mid, ql, qr, val);
if(qr > mid) up(id<<1|1, mid + 1, r, ql, qr, val);
pushup(id);
}
ll qu(int id,int l,int r,int ql,int qr)
{
if(ql <= l && r <= qr) return s[id];
pushdown(id, l, r);
int mid = l + r >> 1;
ll ans = 0;
if(ql <= mid) add(ans, qu(id << 1, l, mid, ql, qr));
if(qr > mid) add(ans, qu(id <<1|1, mid + 1, r, ql, qr));
return ans;
}
void build(int id, int l, int r)
{
if(l == r){
sum[id] = a[ran[l]] % mod;
s[id] = sum[id] * sum[id] % mod;
///printf("l:%d dfn[l]:%d %lld %lld\n", l, dfn[l], sum[id], s[id]);
return ;
}
int mid = l + r >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid+1, r);
pushup(id);
}
int main()
{
n = read(), m = read();
rep(i, 1, n) a[i] = read();
rep(i, 2, n){
int u = read(), v = read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 1);
//rep(i,1,n) printf("i:%d dfn:%d\n",i,dfn[i]);
build(1, 1, n);
while(m--){
int ty = read(), x = read();
int l = dfn[x], r = dfn[x] + sz[x] - 1;
if(ty == 1){
int y = read();
up(1, 1, n, l, r, y);
}
else{
//printf("x:%d dfn:%d l:%d r:%d\n",x,dfn[x],l,r);
printf("%lld\n", qu(1, 1, n, l, r));
}
}
}
E-算式子
做法:参考来自 链接
图片做法来自:博客
x/ai 地方类似于某种差分思想
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
typedef long long ll;
int n, m, x;
ll ans[N], sum[N];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i){
scanf("%d",&x);
sum[x]++;
}
for(int i = 1; i <= m; ++i){
if(!sum[i]) continue;
for(int j = i; j <= m; j += i){
ans[j] += sum[i];
}
}
// for(int i = 1; i <= m; ++i) printf("%lld ",ans[i]);
// puts("");
for(int i = 1; i <= m; ++i) ans[i] += ans[i-1], sum[i] += sum[i-1];
ll res = 0;
for(int i = 1; i <= m; ++i){
//printf("ans:%lld\n",ans[i]);
for(int j = i; j <= m; j+=i){
int l = j, r = min(j + i - 1, m);
ans[i] += (sum[r] - sum[l - 1]) * (j / i);
}
res ^= ans[i];
}
printf("%lld\n", res);
}