首页 > 其他分享 >Codeforces Round #221 (Div. 1) D Tree and Queries

Codeforces Round #221 (Div. 1) D Tree and Queries

时间:2022-09-19 00:33:07浏览次数:99  
标签:hson int siz Tree Codeforces maxn nex Queries now

Tree and Queries

询问 \(V_j\) 的子树中,有多少种颜色出现了 \(K_j\) 次

启发式合并

最直接的,树上启发式合并的同时维护颜色出现的次数,然后再拿一个数组记录一下出现了 \(i\) 次的颜色数量,储存在 \(sum_i\)

对于这个 \(sum\) 的维护,一开始觉得直接套个树状数组上去,复杂度 \(O(nlog^2n)\),直接就莽过去了

后来发现可以直接维护,不需要树状数组,因为我们记录颜色出现的次数必然是从 \(0\) 然后一个个加到最大值 \(cnt_i\) 的过程,因此,这个遍历过程本身就不会缺少,直接将 \(sum_j\) 定义为出现了 \(j\) 次及以上的颜色数量,就会发现非常好维护

时间复杂度为 \(O(nlogn)\)

直接维护:\(O(nlogn)\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
#define pii pair<int, int>
typedef long long ll;
const int maxn = 1e5 + 10;
vector<int>gra[maxn];
int col[maxn], cnt[maxn], fa[maxn];
int siz[maxn], hson[maxn], ans[maxn];
int L[maxn], R[maxn], tp = 0, rnk[maxn];
int sum[maxn];
vector<pii>qs[maxn];

void dfs1(int now, int pre)
{
    L[now] = ++tp;
    fa[now] = pre;
    siz[now] = 1;
    hson[now] = -1;
    rnk[tp] = now;
    for(int nex : gra[now])
    {
        if(nex == pre) continue;
        dfs1(nex, now);
        siz[now] += siz[nex];
        if(hson[now] == -1 || siz[nex] > siz[hson[now]])
            hson[now] = nex;
    }
    R[now] = tp;
}

inline void add(int now)
{
    cnt[col[now]]++;
    sum[cnt[col[now]]]++;
}

inline void del(int now)
{
    sum[cnt[col[now]]]--;
    cnt[col[now]]--;
}

void dfs2(int now, bool keep)
{
    for(int nex : gra[now])
        if(nex != fa[now] && nex != hson[now]) dfs2(nex, false);
    if(hson[now] != -1) dfs2(hson[now], true);
    for(int nex : gra[now])
    {
        if(nex == fa[now] || nex == hson[now]) continue;
        for(int i=L[nex]; i<=R[nex]; i++)
            add(rnk[i]);
    }
    add(now);
    for(auto [k, id] : qs[now])
        ans[id] = sum[k];
    if(!keep)
    {
        for(int i=L[now]; i<=R[now]; i++)
            del(rnk[i]);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i=1; i<=n; i++) cin >> col[i];
    for(int i=1; i<n; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    for(int i=0; i<m; i++)
    {
        int a, b;
        cin >> a >> b;
        qs[a].push_back({b, i});
    }
    dfs1(1, 1);
    dfs2(1, true);
    for(int i=0; i<m; i++)
        cout << ans[i] << "\n";
    return 0;
}

树状数组维护:\(O(nlogn^2n)\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
#define pii pair<int, int>
typedef long long ll;
const int maxn = 1e5 + 10;
vector<int>gra[maxn];
int col[maxn], cnt[maxn], fa[maxn];
int siz[maxn], hson[maxn], ans[maxn];
int L[maxn], R[maxn], tp = 0, rnk[maxn];
vector<pii>qs[maxn];
ll tr[maxn], tot = 0;
int n, m;

inline int lowbit(int x)
{
    return x & (-x);
}

void dfs1(int now, int pre)
{
    L[now] = ++tp;
    fa[now] = pre;
    siz[now] = 1;
    hson[now] = -1;
    rnk[tp] = now;
    for(int nex : gra[now])
    {
        if(nex == pre) continue;
        dfs1(nex, now);
        siz[now] += siz[nex];
        if(hson[now] == -1 || siz[nex] > siz[hson[now]])
            hson[now] = nex;
    }
    R[now] = tp;
}

void update(int now, ll val)
{
    for(int i=now; i<maxn; i+=lowbit(i))
        tr[i] += val;
}

ll query(int now)
{
    ll ans = 0;
    for(int i=now; i; i-=lowbit(i))
        ans += tr[i];
    return ans;
}

inline void add(int now)
{
    if(cnt[col[now]]) update(cnt[col[now]], -1);
    else tot++;
    cnt[col[now]]++;
    update(cnt[col[now]], 1);
}

inline void del(int now)
{
    update(cnt[col[now]]--, -1);
    if(cnt[col[now]]) update(cnt[col[now]], 1);
    else tot--;
}

void dfs2(int now, bool keep)
{
    for(int nex : gra[now])
        if(nex != fa[now] && nex != hson[now]) dfs2(nex, false);
    if(hson[now] != -1) dfs2(hson[now], true);
    for(int nex : gra[now])
    {
        if(nex == fa[now] || nex == hson[now]) continue;
        for(int i=L[nex]; i<=R[nex]; i++)
            add(rnk[i]);
    }
    add(now);
    for(auto [k, id] : qs[now])
        ans[id] = tot - query(k - 1);
    if(!keep)
    {
        for(int i=L[now]; i<=R[now]; i++)
            del(rnk[i]);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for(int i=1; i<=n; i++) cin >> col[i];
    for(int i=1; i<n; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    for(int i=0; i<m; i++)
    {
        int a, b;
        cin >> a >> b;
        qs[a].push_back({b, i});
    }
    dfs1(1, 1);
    dfs2(1, true);
    for(int i=0; i<m; i++)
        cout << ans[i] << "\n";
    return 0;
}

标签:hson,int,siz,Tree,Codeforces,maxn,nex,Queries,now
From: https://www.cnblogs.com/dgsvygd/p/16706381.html

相关文章

  • Codeforces Round #151 (Div. 2) E Blood Cousins Return
    BloodCousinsReturn启发式合并在跑启发式合并的同时,对每个深度都维护一个\(set\),就可以自动去重并计算有多少种不同的字符串#include<iostream>#include<cstdio>......
  • 【题解】CF1311E Construct the Binary Tree
    题目链接-->Problem-E-Codeforces题目大意给定\(n\)和\(d\),你需要构造一棵\(n\)个点的二叉树满足所有点的深度之和恰好为\(d\)。\(2≤n,d≤5000\)。分析......
  • AtCoder Regular Contest 148 C Lights Out on Tree
    挺好的一道题,简单写一下题解吧。首先有挺多很naive的结论:每个节点按两遍等于没按。熄灭所有的灯只有一种方案。其实将灯熄灭的方案无非就是从上往下dfs,如果当前灯......
  • Codeforces Round #816 (Div. 2) A-D
    CodeforcesRound#816(Div.2)A-D传送门A题意:长为n,m的一个棋盘,左上的旗子要去右下,左下的棋子要去右上,每次移动花费为1,但当一个棋子在另一个棋子的轨迹上时,可以花费......
  • Codeforces Round #819 (Div. 1 + Div. 2) A-D
    CodeforcesRound#819(Div.1+Div.2)A-D传送门过程本场A小磕一下,浪费了一点时间,随后B的迷惑题面浪费大量时间,心态发生了变化,不过最后还是在强猜后蒙过了,C又浪费了......
  • Codeforces Round #819 (Div. 1 + Div. 2) 补题 C
    C.Jatayu'sBalancedBracketSequence(思维题)题意:给你一个平衡括号序列(符合书写规则),其任意子区间[i,j]如果是平衡子序列,就建立一条i,j之间的无权无向边,求最后建成的图......
  • Codeforces Round #819 (Div. 1 + Div. 2)
    \(\texttt{Unrated}\)好像是印度老哥又一次放了F原题,悲。A考虑保留头尾的数,\(3\)种情况的分讨,即保留\(a_1\),保留\(a_n\),或者都保留。MyCode#include<bits/stdc+......
  • Codeforces Round #816 (Div. 2)
    Preface早上7:20起来早自习,结果不知道背什么遂刷了好久知乎……下午只有一个思修课,一边划水一遍写题,堪堪做了ABCD晚上据说有C语言的程序设计?又可以摸鱼了好耶A.Crossm......
  • Educational Codeforces Round 40 (Rated for Div. 2) 补题
    E.WaterTaps题意:每个水龙头有一个流量限制\(a_i\),温度\(t_i\),现在让你控制每个水龙头的出水量\(x_i\),使得最终的水温为\(T\),水温的公式为$\frac{\sum\limits_{i=1}^{......
  • CodeForces 限时随机挑战
    挑战规则就是初始难度*2400,积分为\(0\),每次在该难度随机一道题做,每题时限\(35\)分钟,如果没有AC就-1,否则+1,如果积分\(>6\),那么难度\(+100\),积分清零,如果积分\(<......