ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「2021 集训队互测」《关于因为与去年互测zjk撞题而不得不改题这回事》

2022-09-05 15:00:38  阅读:243  来源: 互联网

标签:撞题 sz zjk log int fa lca include 互测


传送门


思路

一个朴素的想法就是 树剖 + 可持久化 trie 树

但这样是 \(O(qm\log^2 V)\) 的,\(30s\) 跑不过去

但我们注意到,我们每次最多访问到前 \(m\log V\) 大的数

我们就可以考虑将前 \(m\log V\) 大的数取出来,从大到小枚举数位,判断是不是有 \(m\) 个数这一位上为 \(1\),如果有,那就将这一位不是 \(1\) 的数全部剔除,再判断下一位

这样单次询问是 \(m\log V \log(m\log V)\) 的

问题是如何快速取出前 \(m\log V\) 大的数

我们考虑开一棵可持久化值域线段树,存的是 \([l,r]\) 的个数

每个结点加入时继承的是它父亲的线段树

在要取出 \((u,v)\) 这条链时,我们就取出 \(u,~v,~ \text{LCA}(u,~v),~Fa_{\text{LCA}(u,~v)}\) 这四颗线段树,进行线段树二分,这样就能取出前 \(,m\log V\) 大的树了

最后的时间复杂度就是 \(O(n\log n+qm\log V \log(m\log V))\)

似乎也只是勉强能过?但实测取出的数并不需要 \(m\log V\) 个,大概 \(200\) 就可以了


代码

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = e[i].nxt)
inline LL reads()
{
    LL sign = 1, re = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
    while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
    return sign * re;
}
int n, m, q;
LL a[1000005], b[1000005], lastans;
struct Node
{
    int to, nxt;
}e[2000005]; int he[1000005];
inline void Edge_add(int u, int v)
{
    static int cnt = 0;
    e[++cnt] = (Node){v, he[u]};
    he[u] = cnt;
}
int fa[1000005][20], dep[1000005], rt[1000005];
int pcnt, ls[25000005], rs[25000005], sz[25000005];
int Ins(int la, int l, int r, int to)
{
    int now = ++pcnt;
    ls[now] = ls[la], rs[now] = rs[la], sz[now] = sz[la] + 1;
    if(l == r) return now;
    int mid = (l + r) >> 1;
    if(to <= mid) ls[now] = Ins(ls[la], l, mid, to);
    else rs[now] = Ins(rs[la], mid + 1, r, to);
    return now;
}
void dfs(int now)
{
    dep[now] = dep[fa[now][0]] + 1;
    rt[now] = Ins(rt[fa[now][0]], 1, m, a[now]);
    PFOR(i, now)
    {
        int to = e[i].to;
        if(to == fa[now][0]) continue;
        fa[to][0] = now;
        dfs(to);
    }
}
inline int LCA(int u, int v)
{
    if(dep[u] < dep[v]) std::swap(u, v);
    ROF(i, 19, 0) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];
    ROF(i, 19, 0) if(fa[u][i] ^ fa[v][i])
        u = fa[u][i], v = fa[v][i];
    return u == v ? u : fa[u][0];
}
LL st[1000005], st1[1000005];
int lim, scnt, scnt1;
void query(int u, int v, int lca, int lcafa, int l, int r)
{
    if(!lim || !(sz[u] + sz[v] - sz[lca] - sz[lcafa])) return;
    if(l == r)
    {
        int add = std::min(lim, sz[u] + sz[v] - sz[lca] - sz[lcafa]);
        while(add--) {st[++scnt] = b[l], lim--;}
        return;
    }
    int mid = (l + r) >> 1;
    query(rs[u], rs[v], rs[lca], rs[lcafa], mid + 1, r);
    query(ls[u], ls[v], ls[lca], ls[lcafa], l, mid);
}
inline void solve(int u, int v, int w)
{
    scnt = 0, lim = 200;
    int lca = LCA(u, v);
    query(rt[u], rt[v], rt[lca], rt[fa[lca][0]], 1, m);
    LL ans = 0;
    ROF(i, 60, 0)
    {
        ans |= (1ll << i);
        scnt1 = 0;
        FOR(j, 1, scnt)
            if((st[j] & ans) == ans)
                st1[++scnt1] = st[j];
        if(scnt1 < w) ans ^= (1ll << i);
        else
        {
            FOR(j, 1, scnt1) st[j] = st1[j];
            scnt = scnt1;
        }
    }
    printf("%lld\n", lastans = ans);
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = reads();
    FOR(i, 1, n - 1)
    {
        int u = reads(), v = reads();
        Edge_add(u, v), Edge_add(v, u);
    }
    FOR(i, 1, n) a[i] = b[i] = reads();
    std::sort(b + 1, b + 1 + n); m = std::unique(b + 1, b + 1 + n) - b - 1;
    FOR(i, 1, n) a[i] = std::lower_bound(b + 1, b + 1 + m, a[i]) - b;
    dfs(1);
    FOR(i, 1, 19) FOR(j, 1, n)
        fa[j][i] = fa[fa[j][i - 1]][i - 1];
    q = reads();
    while(q--)
    {
        int u = reads(), v = reads(), w = reads();
        solve((u ^ lastans) % n + 1, (v ^ lastans) % n + 1, w);
    }
    return 0;
}

标签:撞题,sz,zjk,log,int,fa,lca,include,互测
来源: https://www.cnblogs.com/zuytong/p/16658158.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有