【每日一题】8月20日华华和月月种树,树状数组+差分+DFS序

华华和月月种树

https://ac.nowcoder.com/acm/problem/23051

参考题解

题目意思

第一行一个T,代表总操作数T,T<4e5
后面有T行,分三种情况。第一个数是1,生成一个新的节点挂在第二个数的子节点位置,编号为第几次操作1就是几。
第二种情况是第一个数为2,把第二个数以及全部子树权值都增加第三个数大小。
第三种情况是第一个数是3,直接输出第二个数的权值。

Solution

动态建树,以及区间改动,并不好实现。我们采取一种离线的做法。
在输入的时候,保存好操作信息,主要就是保存好下面代码中的b[i]数组。
用vector模拟建树,用DFS序表示每个节点掌控的数字下标范围。
操作2就是常规的树状数组区间改变。
在每次操作1中用另外的一个数组,初始化值为负的父节点权值,这样下次树状数组累加的时候就能初始化这个节点值为0了。

#pragma GCC target("avx,sse2,sse3,sse4,popcnt")
#pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math")
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline int lowbit(int x) { return x & (-x); }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;

const int N = 4e5 + 7;
vector<int> g[N];
int l[N], r[N], val[N], cnt;


int c[N];
void add(int i, int x) {
    for (; i < N; i += lowbit(i))    c[i] += x;
}

int query(int i) {
    int ret = 0;
    for (; i; i -= lowbit(i))    ret += c[i];
    return ret;
}

int op[N], a[N], b[N];

void dfs(int u) {
    l[u] = ++cnt;
    for (auto it : g[u]) {
        dfs(it);
    }
    r[u] = cnt;
}

int main() {
    int T = read();
    for (int i = 1; i <= T; ++i) {
        op[i] = read(), a[i] = read();
        if (op[i] == 1) {
            g[a[i]].push_back(++cnt);
            b[i] = cnt;
        }
        else if (op[i] == 2)    b[i] = read();
    }
    cnt = 0;
    dfs(0);
    for (int i = 1; i <= T; ++i) {
        if (op[i] == 1)
            val[l[b[i]]] = -query(l[a[i]]);
        else if (op[i] == 2) {
            add(l[a[i]], b[i]);
            add(r[a[i]] + 1, -b[i]);
        }
        else
            print(val[l[a[i]]] + query(l[a[i]]));
    }
    return 0;
}
每日一题 文章被收录于专栏

每日一题

全部评论

相关推荐

来,说点可能被同行“骂”的大实话。🙊当初接数字马力Offer时,朋友都说:“蚂蚁的“内包”公司?你想清楚啊!”但入职快一年后的今天,我反而对他有了不一样的看法!🔹&nbsp;是偏见?还是信息差!之前没入职之前外面都在说什么岗位低人一等这类。实际上:这种情况不可至否,不能保证每个团队都是其乐融融。但我在的部门以及我了解的周边同事都还是十分好相处的~和蚂蚁师兄师姐之间也经常开一些小玩笑。总之:身份是蚂蚁公司给的,地位是自己挣的(一个傲娇女孩的自述)。🔹&nbsp;待遇?玩的就是真实!试用期工资全额发!六点下班跑得快(早9晚6或者早10晚7,动态打卡),公积金顶格交。别听那些画饼的,到手的钱和下班的时间才是真的(都是牛马何必难为牛马)。🔹&nbsp;能不能学到技术?来了就“后悔”!我们拥有权限直通蚂蚁知识库,技术栈多到学不完。说“学不到东西”的人,来了可能后悔——后悔来晚了(哈哈哈哈,可以不学但是不能没有)!💥&nbsp;内推地址:https://app.mokahr.com/su/ueoyhg❗我的内推码:NTA6Nvs走我的内推,可以直达业务部门,面试流程更快速,进度可查!今天新放HC,之前挂过也能再战!秋招已经正式开始啦~机会就摆在这,敢不敢来试一试呢?(和我一样,做个勇敢的女孩)
下午吃泡馍:数字马力的薪资一般哇,5年经验的java/测试就给人一万出头,而且刚入职第三天就让人出差,而且是出半年
帮你内推|数字马力 校招
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务