HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390

看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对。

其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加。

所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值。

这样还会被卡MLE。。 需要分层优化一下。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;}

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int LOG = 30;

int n, m, v[N], tmp[N];
int qus[N][3];
int ans[N];
int Trietot;
int ch[N * 40][2], sz[N * 40];
int mx = 0;
int newNode() {
    Trietot++;
    assert(Trietot < N * 40);
    chkmax(mx, Trietot);
    ch[Trietot][0] = 0;
    ch[Trietot][1] = 0;
    sz[Trietot] = 0;
    return Trietot;
}

struct Trie {
    int Rt;
    void init() {
        Rt = newNode();
    }
    void ins(int x) {
        int u = Rt;
        for(int i = LOG - 1; i >= 0; i--) {
            sz[u]++;
            if(!ch[u][x >> i & 1]) {
                ch[u][x >> i & 1] = newNode();
            }
            u = ch[u][x >> i & 1];
        }
        sz[u]++;
    }
    void del(int x) {
        int u = Rt;
        for(int i = LOG - 1; i >= 0; i--) {
            sz[u]--;
            u = ch[u][x >> i & 1];
        }
        sz[u]--;
    }
    int query(int x) {
        int u = Rt, ret = 0;
        if(!sz[u]) return 0;
        for(int i = LOG - 1; i >= 0; i--) {
            if(sz[ch[u][(x >> i & 1) ^ 1]]) {
                ret += 1 << i;
                u = ch[u][(x >> i & 1) ^ 1];
            }
            else {
                u = ch[u][x >> i & 1];
            }
        }
        return ret;
    }
} T[N << 2];

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
void build(int tar, int cur, int l, int r, int rt) {
    if(cur == tar) {
        T[rt].init();
        return;
    }
    if(l == r) return;
    int mid = l + r >> 1;
    build(tar, cur + 1, lson);
    build(tar, cur + 1, rson);
}
void update(int tar, int cur, int L, int R, int val, int l, int r, int rt) {
    if(L > R) return;
    if(L <= l && r <= R) {
        if(cur == tar) {
            if(val > 0) T[rt].ins(val);
            else T[rt].del(-val);
        }
        return;
    }
    if(l == r) return;
    int mid = l + r >> 1;
    if(L <= mid) update(tar, cur + 1, L, R, val, lson);
    if(R > mid) update(tar, cur + 1, L, R, val, rson);
}

int query(int tar, int cur, int p, int val, int l, int r, int rt) {
    if(cur == tar) {
        return T[rt].query(val);
    }
    if(l == r) return 0;
    int mid = l + r >> 1;
    if(p <= mid) return query(tar, cur + 1, p, val, lson);
    else return query(tar, cur + 1, p, val, rson);
}

void initTrie(int depth) {
    Trietot = 0;
    build(depth, 0, 1, n, 1);
}

vector<int> G[N];
int in[N], ot[N], idx;

void dfs(int u) {
    in[u] = ++idx;
    for(auto &v : G[u]) {
        dfs(v);
    }
    ot[u] = idx;
}

void init() {
    idx = 0;
    for(int i = 1; i <= n; i++) {
        G[i].clear();
    }
}

int main() {
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        init();
        for(int i = 2; i <= n; i++) {
            int par; scanf("%d", &par);
            G[par].push_back(i);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &v[i]);
            tmp[i] = v[i];
        }
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &qus[i][0], &qus[i][1]);
            if(qus[i][0] == 0) scanf("%d", &qus[i][2]);
            ans[i] = 0;
        }
        dfs(1);
        for(int depth = 0; depth <= 17; depth++) {
            initTrie(depth);

            for(int i = 1; i <= n; i++) {
                v[i] = tmp[i];
                update(depth, 0, in[i], ot[i], v[i], 1, n, 1);
            }
            for(int i = 1; i <= m; i++) {
                if(!qus[i][0]) {
                    update(depth, 0, in[qus[i][1]], ot[qus[i][1]], -v[qus[i][1]], 1, n, 1);
                    v[qus[i][1]] = qus[i][2];
                    update(depth, 0, in[qus[i][1]], ot[qus[i][1]], v[qus[i][1]], 1, n, 1);
                }
                else {
                    chkmax(ans[i], query(depth, 0, in[qus[i][1]], v[qus[i][1]], 1, n, 1));
                }
            }
        }

        for(int i = 1; i <= m; i++) {
            if(qus[i][0]) {
                printf("%d\n", ans[i]);
            }
        }
    }
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/11183306.html

时间: 2024-10-10 03:47:46

HDU - 5390 tree 线段树套字典树 (看题解)的相关文章

HDU 1247 Hat&#39;s Words (字典树)

[题目链接]click here~~ [题目大意]A hat's word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary. ,找出由两个子字符串组成的字符串. [解题思路]字典树 #include <bits/stdc++.h> using namespace std; const int N=5*1e4+100; const int MOD=

hdu 1247:Hat’s Words(字典树,经典题)

Hat's Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7282    Accepted Submission(s): 2639 Problem Description A hat's word is a word in the dictionary that is the concatenation of exactly

HDU 1247 Hat&#39;s words(字典树Trie)

解题思路: 判断给出的单词是否恰好由另外两个单词组成,用栈保存每个子字符串的节点,从这个节点出发判断剩下的字符串是否在字典树中即可. #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <sta

BZOJ 3217 ALOEXT 替罪羊树套Trie树

题目大意:维护一个序列,支持以下操作: 1.在某个位置插入一个数 2.删除某个位置上的数 3.修改某个位置上的数 4.求某段区间中的次大值与区间中另一个数的异或值的最大值 强制在线 替罪羊树套Trie树...终于尼玛A了...7.4KB的大代码啊- - 插入和修改同带插入区间k小值 删除要打标记不能直接删 删除的时候注意 删除导致的不平衡不要重建 否则复杂度无法保证 因此每个节点维护一个max_size代表历史size最大值 判断不平衡时用这个变量来判断即可 注意访问替罪羊树的时候一定要判断当前

trie树(字典树)

1. trie树,又名字典树,顾名思义,它是可以用来作字符串查找的数据结构,它的查找效率比散列表还要高. trie树的建树: 比如有字符串"ab" ,"adb","adc"   可以建立字典树如图: 树的根节点head不存储信息,它有26个next指针,分别对应着字符a,b,c等.插入字符串ab时,next['a'-'a']即next[0]为空,这是申请一个结点放在next[0]的位置,插入字符串db时,next['d'-'a']即next[3]

poj 3630 Phone List (字典树 +静态字典树)

Phone List Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22235   Accepted: 6885 Description Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogu

【bzoj3217】ALOEXT 替罪羊树套Trie树

题目描述 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手. 突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数.taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的).不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直

【HDU 6191】Query on A Tree 【可持久化字典树】

题目 给出一棵有n个结点的树,树根是1,每个结点给出一个value.然后给出q个询问,每个询问给出两个整数u和x,你要在以u结点为根的子树中找出一个结点v,使得val[v] xor x最大, 并输出这个最大值 分析 显而易见的可持久化字典树,只不过这次每次查询不是查询一个区间,而是查询一棵子树.那么也很简单,我们只要预处理出dfs序然后找出每个结点以它为根的子树在dfs序中的区间.然后以这个区间建可持久化字典树就可以了. 1 #include <cstdio> 2 #include <c

ACM学习历程—HDU 5536 Chip Factory(xor &amp;&amp; 字典树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536 题目大意是给了一个序列,求(si+sj)^sk的最大值. 首先n有1000,暴力理论上是不行的. 此外题目中说大数据只有10组,小数据最多n只有100.(那么c*n^2的复杂度应该差不多) 于是可以考虑枚举i和j,然后匹配k. 于是可以先把所有s[k]全部存进一个字典树, 然后枚举s[i]和s[j],由于i.j.k互不相等,于是先从字典树里面删掉s[i]和s[j],然后对s[i]+s[j]这个