Codeforces 600E. Lomset Gelral(树上莫队)

这道题是群友给的,今天无聊就去搞一搞

其实遇到树上的题,我们一般都会把树上的东西给dfs序重新建链再做

然后这道题本身在想怎么用树链剖分维护,老套路打时间戳然后跟着轻重儿子搞两次dfs,类似于滑动窗口那样从一个节点开始dfs,每次先把子树全部装进滑动窗口,然后当我们dfs到下一个节点的时候就把父亲节点扔了然后计算贡献,这样一来就行了

但有个问题,一个树可能有多叉,那么显然任意一节点u的子树未必是儿子v的子树,答案正确性无法保证,而且如果重新装,那就是O(n^2)的,显然不太行

后来发现维护个蛋啊,这个剪掉的过程不就是莫队么?(

然后愉快地ac了,莫队函数基本套用以前的求众数,只不过对于每一cnt i 多维护一下color就行了

代码:

#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
#define debug(x) cout<<x<<endl
typedef long long ll;
typedef unsigned long long ull;
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
inline ll read(){
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = (x << 3) + (x << 1) + s - '0';s = getchar();}
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if(x/ 10) print(x / 10);
    *O++=x % 10+'0';
}
void write(ll x, char c = 't') {
    if(x < 0)putchar('-'),x = -x;
    print(x);
    if(!isalpha(c))*O++ = c;
    fwrite(obuf,O-obuf,1,stdout);
    O = obuf;
}
int kase;
int n, m, k;
int a[limit];
vector<int>g[limit];
int id[limit], eid[limit];
int cnt[limit], sum[limit], ans[limit];
int tot;
int fa[limit], depth[limit];
int sizes[limit], son[limit];
void dfs(int u, int pre = 0){
    sizes[u] = 1;
    fa[u] = pre;
    depth[u] = depth[pre] + 1;
    for(auto v : g[u]){
        if(v == pre)continue;
        dfs(v,u);
        sizes[u] += sizes[v];
        if (sizes[son[u]] < sizes[v])son[u] = v;
    }
}
int ret[limit];
int color[limit];
int back[limit];
void dfs2(int u, int tp){
    id[u] = ++tot;
    color[id[u]] = a[u];
    back[id[u]] = u;
    if(son[u])dfs2(son[u],tp);
    for(auto v : g[u]){
        if(v != son[u] && v != fa[u])dfs2(v,v);
    }
    eid[u] = tot;//结尾
}
int res = 0;
void add(int x){
    ans[cnt[color[x]]] -= color[x];
    --sum[cnt[color[x]]];//减去多余部分
    ++cnt[color[x]];//增加一个count
    res = max(res, cnt[color[x]]);
    ++sum[cnt[color[x]]];
    ans[cnt[color[x]]] += color[x];
}
void del(int x){
    ans[cnt[color[x]]] -= color[x];
    --sum[cnt[color[x]]];//撤回一个count
    if(res == cnt[color[x]] and !sum[cnt[color[x]]])--res;//如果没有了那就增加
    --cnt[color[x]];
    ++sum[cnt[color[x]]];
    ans[cnt[color[x]]] += color[x];
}
struct node{
    int l, r, qid, blo;
    bool operator<(const node &rhs)const{
        if(blo ^ rhs.blo)return l < rhs.l;
        return blo & 1 ? r < rhs.r : rhs.r < r;
    }
}query[limit];
void solve(){
    n = read();
    rep(i,1,n){
        a[i] = read();
        ans[0] += a[i];
    }
    rep(i,1,n-1){
        int x,y;
        x = read();
        y = read();
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs(1,0);
    dfs2(1,1);
    int block = int(sqrt(n >= 3 ? n * (2.0 / 3) : n));//分块
    rep(i, 1, n){
        query[i].l = id[i], query[i].r = eid[i], query[i].qid = i;
        query[i].blo = query[i].l / block;//分成块
    }
    sort(query + 1, query + 1 + n);
    int l = 0 , r = 0;
    rep(i ,1, n){
        while(l < query[i].l)del(l++);//缩进
        while(l > query[i].l)add(--l);
        while(r < query[i].r)add(++r);
        while(r > query[i].r)del(r--);
        ret[query[i].qid] = ans[res];
    }
    rep(i,1,n){
        write(ret[i],' ');
    }
}
int32_t main() {
#ifdef LOCAL
    FOPEN;
    //FOUT;
#endif
    //FASTIO
    //cin>>kase;
    //while (kase--)
    solve();
    cerr << "Time elapsed: " << 1.0*clock()/CLOCKS_PER_SEC << "s\n";
    return 0;
}

 

posted @ 2021-04-26 13:18  tiany7  阅读(62)  评论(0编辑  收藏  举报