题目:
给你一棵根为1的有N个节点的树,以及Q次操作。
每次操作诸如:
1 x y:将节点x所在的子树的所有节点的权值加上y
2 x:询问x所在子树的所有节点的权值的平方和,答案模23333后输出
输入:
第一行两个整数N,Q
第二行N个整数,第i个表示节点i的初始权值
接下来N-1行每行两个整数u,v,表示u和v之间存在一条树边
接下来Q行每行一个操作,格式如题目描述
输出描述:
对于每个询问操作,输出一行一个整数,表示答案在模23333后的结果
分析:
很模版的一道题有很多方法可以写,这里我用的是树链剖分+线段树。两编dfs,第一遍获得子树大小,每个节点父亲,深度。
第二遍获得dfn序,重链top(不需要主要是因为在练板子所以写了)以及入栈时间(tmp)所对应的点,相当于逆映射吧。
这题不是很难,只是我写的有很多问题记录一下。取余运算没有每个都写导致爆了long long,其实改一下就行,我比较懒就开了int128,然后修改和查询操作因为我没有记录每个点出去的时间,我是用的一个siz数组存子树大小,在区间修改个查询的时候应该是dfn[x]-----dfn[x]+siz[x]-1,一开始没有减一导致答案错误,还是记录出去的位置更方便
模运算没有处理好的代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int mod = 23333;
const int maxn = 1e5+10;
int n,q;
int a[maxn];
vector<int>g[maxn];
int fa[maxn],siz[maxn],dep[maxn],son[maxn];
void dfs1(int x,int f){
fa[x]=f;
siz[x]=1;
dep[x]=dep[f]+1;
for(auto y:g[x]){
if(y==f) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
int tmp=0;
int dfn[maxn],ff[maxn],top[maxn];
void dfs2(int x,int f,int tp){
dfn[x]=++tmp;
ff[tmp]=x;
top[x]=tp;
if(son[x]!=0) dfs2(son[x],x,tp);
for(auto y:g[x]){
if(y==f||y==son[x]) continue;
dfs2(y,x,y);
}
}
struct ty{
i64 sum,squared;
}tree[maxn<<2];
int lazy[maxn];
void pushup(int p,int l,int r){
tree[p].sum = (tree[p*2].sum+tree[p*2+1].sum)%mod;
tree[p].squared=(tree[p*2].squared+tree[p*2+1].squared)%mod;
}
void build(int p,int l,int r){
if(l==r){
tree[p].sum=a[ff[l]]%mod;
tree[p].squared=(a[ff[l]]%mod*a[ff[l]]%mod)%mod;
return;
}
int mid = (l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p,l,r);
}
void pushdown(int p,int l,int r){
int num = lazy[p]%mod;
int mid = (l+r)>>1;
lazy[p*2]+=num;
lazy[p*2+1]+=num;
tree[p*2].squared+=(tree[p*2].sum%mod*2LL*num%mod+(mid-l+1)*num%mod*num%mod)%mod;
tree[p*2].sum+=(mid-l+1)*num%mod;
tree[p*2+1].squared+=(tree[p*2+1].sum%mod*2LL*num%mod+(r-mid)*num%mod*num%mod)%mod;
tree[p*2+1].sum+=(r-mid)*num%mod;
lazy[p]=0;
}
void change(int p,int l,int r,int x,int y,int num){
if(x<=l&&r<=y){
lazy[p]+=num%mod;
tree[p].squared+=(2LL*num%mod*tree[p].sum%mod+num%mod*num%mod*(r-l+1)%mod)%mod;
tree[p].sum+=(r-l+1)*num%mod;
return;
}
if(lazy[p]!=0) pushdown(p,l,r);
int mid = (l+r)>>1;
if(x<=mid) change(p*2,l,mid,x,y,num);
if(y>mid) change(p*2+1,mid+1,r,x,y,num);
pushup(p,l,r);
}
i64 query(int p,int l,int r,int x,int y){
if(x<=l&&r<=y) return tree[p].squared%mod;
int mid =(l+r)>>1;
if(lazy[p]!=0)pushdown(p,l,r);
i64 ans=0;
if(x<=mid) ans+=query(p*2,l,mid,x,y)%mod;
if(y>mid) ans+=query(p*2+1,mid+1,r,x,y)%mod;
return ans;
}
int main(){
ios;
cin>>n>>q;
for(int i = 1;i<=n;++i)cin>>a[i];
for(int i =1;i<n;++i){
int x,y;cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1,0);
dfs2(1,0,1);
build(1,1,n);
for(int i = 1;i<=q;++i){
int op;
cin>>op;
if(op==1){
int x,y;
cin>>x>>y;
change(1,1,n,dfn[x],dfn[x]+siz[x]-1,y);
}else{
int x;cin>>x;
cout<<query(1,1,n,dfn[x],dfn[x]+siz[x]-1)%mod<<"\n";
}
}
return 0;
AC的代码(写的属实丑陋)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define int __int128
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
template <typename T>
inline T read() {
T sum = 0, fl = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar())
sum = sum * 10 + (ch - '0'); // 修改此处
return sum * fl;
}
template <typename T>
inline void write(T x) { // 修改返回类型为 void
static int sta[45];
int cnt = 0;
if (x < 0) putchar('-'), x = -x; // 处理负数
do {
sta[cnt++] = x % 10, x /= 10;
} while (x);
while (cnt) putchar(sta[--cnt] + '0');
}
const int mod = 23333;
const int maxn = 1e6+10;
int n,q;
int a[maxn];
vector<int>g[maxn];
int fa[maxn],siz[maxn],dep[maxn],son[maxn];
void dfs1(int x,int f){
fa[x]=f;
siz[x]=1;
dep[x]=dep[f]+1;
for(auto y:g[x]){
if(y==f) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
int tmp=0;
int dfn[maxn],ff[maxn],top[maxn];
void dfs2(int x,int f,int tp){
dfn[x]=++tmp;
ff[tmp]=x;
top[x]=tp;
if(son[x]!=0) dfs2(son[x],x,tp);
for(auto y:g[x]){
if(y==f||y==son[x]) continue;
dfs2(y,x,y);
}
}
struct ty{
i64 sum,squared;
}tree[maxn<<2];
int lazy[maxn];
void pushup(int p,int l,int r){
tree[p].sum = (tree[p*2].sum+tree[p*2+1].sum)%mod;
tree[p].squared=(tree[p*2].squared+tree[p*2+1].squared)%mod;
}
void build(int p,int l,int r){
if(l==r){
tree[p].sum=a[ff[l]]%mod;
tree[p].squared=(a[ff[l]]%mod*a[ff[l]]%mod)%mod;
return;
}
int mid = (l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p,l,r);
}
void pushdown(int p,int l,int r){
int num = lazy[p]%mod;
int mid = (l+r)>>1;
lazy[p*2]+=num;
lazy[p*2+1]+=num;
tree[p*2].squared+=(tree[p*2].sum%mod*2LL*num%mod+(mid-l+1)*num%mod*num%mod)%mod;
tree[p*2].sum+=(mid-l+1)*num%mod;
tree[p*2+1].squared+=(tree[p*2+1].sum%mod*2LL*num%mod+(r-mid)*num%mod*num%mod)%mod;
tree[p*2+1].sum+=(r-mid)*num%mod;
lazy[p]=0;
}
void change(int p,int l,int r,int x,int y,int num){
if(x<=l&&r<=y){
lazy[p]+=num%mod;
tree[p].squared+=(2LL*num%mod*tree[p].sum%mod+num%mod*num%mod*(r-l+1)%mod)%mod;
tree[p].sum+=(r-l+1)*num%mod;
return;
}
if(lazy[p]!=0) pushdown(p,l,r);
int mid = (l+r)>>1;
if(x<=mid) change(p*2,l,mid,x,y,num);
if(y>mid) change(p*2+1,mid+1,r,x,y,num);
pushup(p,l,r);
}
i64 query(int p,int l,int r,int x,int y){
if(x<=l&&r<=y) return tree[p].squared%mod;
int mid =(l+r)>>1;
if(lazy[p]!=0)pushdown(p,l,r);
i64 ans=0;
if(x<=mid) ans+=query(p*2,l,mid,x,y)%mod;
if(y>mid) ans+=query(p*2+1,mid+1,r,x,y)%mod;
return ans;
}
signed main(){
n = read<int>();
q = read<int>();
for(int i = 1;i<=n;++i)a[i] = read<int>();;
for(int i =1;i<n;++i){
int x,y;
x = read<int>();y = read<int>();
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1,0);
dfs2(1,0,1);
build(1,1,n);
for(int i = 1;i<=q;++i){
int op;
op = read<int>();
if(op==1){
int x,y;
x= read<int>();y = read<int>();
change(1,1,n,dfn[x],dfn[x]+siz[x]-1,y);
}else{
int x;x = read<int>();
write<int>(query(1,1,n,dfn[x],dfn[x]+siz[x]-1)%mod);
printf("\n");
}
}
return 0;
}