zoukankan      html  css  js  c++  java
  • 牛客算法周周练15D

    在这里插入图片描述在这里插入图片描述

    题目大意:

    输入n q 表示树有 n 个节点和 q 次操作,然后输入n个数,表示 n 个节点的权值,之后输入 n - 1 条边,再输入 q 次操作,1 x y表示给 x 所在的子树权值 + y,2 x 则输出 x所在子树的所有节点的平方和

    解题思路:

    树上问题的模板题,遇到树,而且是在子树上进行操作,先跑一遍dfs序将这棵树线性化,因为dfs序跑完以后,子数部分一定是连续的,而且可以求出该节点所在子树的起始时间戳和终止时间戳,然后子树上的问题就转化为对区间进行操作的问题了,维护一个平方和,愉快的使用线段树即可。

    关于dfs序:
    这道题需要先跑dfs序线性化,在dfs序中有这样几个值,in数组,in[x] 表示x节点进入序列的时间戳,out[x] 表示x从序列中出去的时间戳,in[x] -> out[x]即可表示 x 的子树,还有一个数组dfsn 表示遍历顺序,也就是树线性化后的数组。

    关于线段树维树平方和问题:
    该题维护的是平方和,也就是对于每个节点,是要变为 (a+y)2
    而不是a2+y2,推一个公式:
    平方和(a+b)2 = a2 + 2ab + b2,然而对于这道题来说,就可以转换为
    Σa2 + 2 ·Σa · len · y + Σy2
    ,len表示区间长度。单点的原始值则是(Σa + len * b),lazy中存y的值,sum1 表示区间原始值, sum2 表示区间平方和, 推的时候一定要先推平方和,因为平方和是由原始值转化过来的,如果先推原始值会出错。这些都求完后,套用线段树模板即可,注意数据范围适当开long long 和随时对23333取模,因为这个点调试了一晚上加一上午才调好。AC代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    using namespace std;
    const int N = 1e5+50;
    const int mod = 23333;
    typedef long long ll;
    ll lazy[N << 2] = {0}, sum1[N << 2] = {0}, sum2[N << 2] = {0};
    int tot = 0, n, q;
    int in[N], out[N], dfsn[N], a[N];
    vector<int > v[N];
    void dfsx(int x, int pre)
    {
    	in[x] = ++tot;
    	dfsn[tot] = x;
    	for (int i = 0; i < v[x].size(); i ++)
    	{
    		int j = v[x][i];
    		if (j != pre)
    		  dfsx(j,x);
    	}
    	out[x] = tot;
    }
    void pushup(int node)
    {
    	sum1[node] = (sum1[node << 1] + sum1[node << 1|1]) % mod;
    	sum2[node] = (sum2[node << 1] + sum2[node << 1|1]) % mod;
    }
    void build(int node, int l, int r)
    {
    	if (l == r)
    	{
    		sum1[node] = a[dfsn[l]] % mod;
    		sum2[node] = (sum1[node] * sum1[node]) % mod;//这里玄学,用a[dfsn[l]] % mod会WA,用sum1[node] 则不会..
    		return;
     	}
    	int mid = (l + r) >> 1;
    	build(node << 1, l, mid);
    	build(node << 1|1, mid+1, r);
    	pushup(node);
    }
    void pushdown(int node, int l, int r)//利用推好的公式还原相应的值
    {
    	if (!lazy[node]) return;
    	int mid = (l + r) >> 1;
    	lazy[node << 1] = (lazy[node << 1] + lazy[node]) % mod;
    	lazy[node << 1|1] = (lazy[node << 1|1] + lazy[node]) % mod;
    	sum2[node << 1] = (sum2[node << 1] + (lazy[node] * lazy[node] * (mid - l + 1)) % mod + (2 * lazy[node] % mod * sum1[node << 1] % mod) % mod) % mod;
    	sum2[node << 1|1] = (sum2[node << 1|1] + (lazy[node] * lazy[node] * (r - mid)) % mod + (2 * lazy[node] % mod * sum1[node << 1|1] % mod) % mod) % mod;
    	sum1[node << 1] = (sum1[node << 1] + (mid - l + 1) * lazy[node]) % mod;
    	sum1[node << 1|1] = (sum1[node << 1|1] + (r - mid) * lazy[node]) % mod;
    	lazy[node] = 0;
    }
    void update(int node ,int l, int r, int L, int R,int val)
    {
    	if (l >= L && r <= R)
    	{
    		lazy[node] = (lazy[node] % mod + val) % mod;
    		sum2[node] = (sum2[node] + val % mod * val % mod * (r - l + 1) % mod + 2 * val % mod * sum1[node] % mod) % mod;
    		sum1[node] = (sum1[node] + (r - l + 1) * val % mod) % mod;
    		return;
    	}
    	pushdown(node, l, r);
    	int mid = (l + r) >> 1;
    	if (L <= mid) 
    	  update(node << 1, l, mid, L, R, val);
    	if (R > mid)
    	  update(node << 1|1, mid + 1, r, L, R, val);
    	pushup(node);
    }
    ll query(int node, int l, int r, int L, int R)
    {
    	if (l >= L && r <= R)
    	  return sum2[node] % mod;
    	pushdown(node, l, r);
    	int mid = (l + r) >> 1;
    	ll s1 = 0, s2 = 0;
    	if (L <= mid)
    	  s1 += query(node << 1, l, mid, L, R) % mod;
    	if (R > mid)
    	  s2 += query(node << 1|1, mid + 1, r, L, R) % mod;
    	return (s1 + s2) % mod;
    }
    int main()
    {
    	cin >> n >> q;
    	for (int i = 1; i <= n; i ++)
    		cin >> a[i];
    	for(int i = 1; i < n; i ++)
    	{
    		int e1, e2;
    		cin >> e1 >> e2;
    		v[e1].push_back(e2);
    		v[e2].push_back(e1);
    	}
    	dfsx(1, 0);
    	build(1, 1, n);
     	while (q--)
    	{
    		int cmd, b, c;
    		cin >> cmd;
    		if (cmd == 1)
    		{
    			cin >> b >> c;
    			c %= mod;
    			update(1, 1, n, in[b], out[b], c);
    		}
    		else
    		{
    			cin >> b;
    			ll ans = query(1, 1, n, in[b], out[b]);
    			cout << ans << endl;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    RabbitMQ与AMQP协议详解
    MemCache超详细解读
    ASP.NET Web API通过ActionFilter来实现缓存
    ASP.NET Web API 通过Authentication特性来实现身份认证
    什么是CSR证书申请文件?
    跨平台的 SQL 客户端
    Java生成公私钥对
    git 删除错误提交的commit
    ServiceStack.Text反序列化lowercase_underscore_names格式的JSON
    .NET AES加解密(128位)
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294211.html
Copyright © 2011-2022 走看看