树上求和 牛客

题目:
给你一棵根为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;
}

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值