zoukankan      html  css  js  c++  java
  • [Codeforces] E. Lomsat gelral #DSU on Tree

    E. Lomsat gelral

    time limit per test 2 seconds
    memory limit per test 256 megabytes
    input standard input
    output standard output
     

    You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.

    Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.

    The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.

    For each vertex v find the sum of all dominating colours in the subtree of vertex v.

    Input

    The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.

    The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.

    Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.

    Output

    Print n integers — the sums of dominating colours for each vertex.

    Examples
    input
    4
    1 2 3 4
    1 2
    2 3
    2 4
    output
    10 9 3 4
    input
    15
    1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
    1 2
    1 3
    1 4
    1 14
    1 15
    2 5
    2 6
    2 7
    3 8
    3 9
    3 10
    4 11
    4 12
    4 13
    output
    6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

    Analysis

    Emmmm据说出题人搞出了DSU on Trees 还拿来出题了

    (好在我没打这一场)

    顺路解释什么是Dsu on Tree

    首先我们要解决的问题是诸如此类的:在一棵树上,对每一个结点的子树进行计数(比如符合条件的结点的数量)

    如果这个东西出的坑一点,我们(啊,应该是只有我这种弱鸡)就不得不对每一个结点统计子树,显然复杂度 O(n2)

    那么Dsu on tree 就是为了优化这种情况而出现的

    为什么会有重复计数呢?这可能是因为我们要计数的最终答案会因为计数结果而发生改变,因此对于子树不同的结点很难用同一个存储容器进行计数

    现在有两个结点: U 和 V ,U 是 V 的父结点

    那么 V 的计数结果,最终也会被包含到 U 的计数结果里(U 计数的时候会覆盖 V 以及 V 的子树)

    联系暴力的流程:我们需要在计数之后,清除当前这棵子树的计数(因为全程用的都是同一个容器(数组))

    那么我们记完 V 回溯到 U 的时候,就没必要清除 V 子树的计数了,以此减小复杂度

    所以每次都保留重儿子(其子树结点数量最大的子结点)的计数,清除轻儿子的计数

    联系树链剖分的相关结论,我们可以精确地得知这么做所能带来的复杂度上的优化程度

    以上就是DSU on Tree 的本质了

    那么我们拔高一个层次

    1 树上启发式合并,或称树上并查集(垃圾翻译我还是喜欢树上启发式)
    2 启发式合并,即通过将较小的对象合并至较大的对象以减小复杂度(个人理解)
    3 在以上讨论中,启发式合并具体体现为将轻儿子的信息合并至没有消除影响的重儿子上
    什么是Dsu on Tree?

    本文主要为对DSU的个人理解 :)

    Code

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<vector>
      4 #define maxn 1000000
      5 #define LL long long
      6 using namespace std;
      7 
      8 vector<int> G[maxn];
      9 
     10 int TIM,mx,n,L[maxn],R[maxn],son[maxn],sz[maxn],line[maxn*3],cnt[maxn],color[maxn];
     11 LL result[maxn],ans[maxn];
     12 
     13 void dfs(int u,int fa){
     14 //    printf("Now in #%d
    ",u); 
     15     sz[u] = 1; L[u] = ++TIM; line[TIM] = color[u];
     16     for(int i = 0;i < G[u].size();i++){
     17         if(G[u][i] == fa) continue;
     18         int v = G[u][i];
     19         dfs(v,u);
     20         sz[u] += sz[v];
     21         if(!son[u]||sz[v]>sz[son[u]])
     22             son[u] = v;
     23     }R[u] = TIM;
     24 }
     25 
     26 void Add(int u,int &mx){
     27     for(int i = L[u];i <= R[u];i++){
     28         result[cnt[line[i]]] -= line[i];
     29         cnt[line[i]]++;
     30         result[cnt[line[i]]] += line[i];
     31         mx = max(cnt[line[i]],mx);
     32     }
     33 }
     34 
     35 void Del(int u){
     36     for(int i = L[u];i <= R[u];i++){
     37         result[cnt[line[i]]] -= line[i];
     38         cnt[line[i]]--;
     39         result[cnt[line[i]]] += line[i];
     40     }
     41 }
     42 
     43 /*void Add(int x,int &mx){
     44     for(int i=L[x];i<=R[x];++i){
     45         result[++cnt[line[i]]]+=color[line[i]];
     46         max(mx,cnt[line[i]]);
     47     }
     48 }
     49 
     50 void Del(int x,int &mx){
     51     for(int i=L[x];i<=R[x];++i){
     52         if(cnt[color[line[i]]]==mx)--mx;
     53         result[cnt[color[line[i]]]--]-=color[line[i]];
     54     }
     55 }*/
     56 
     57 // 10 9 3 4
     58 void dsu(int u,int fa){
     59 //    printf("Now in #%d son[%d]: %d
    ",u,u,son[u]);
     60     mx = 0;
     61     for(int i = 0;i < G[u].size();i++){
     62         if(G[u][i] == fa || G[u][i] == son[u]) continue;
     63         dsu(G[u][i],u);
     64 //        Add(G[u][i],mx);
     65         Del(G[u][i]);
     66         
     67 //        cout << "Now A" << endl;
     68 //        printf("#%d color_cnt: ",u); for(int l = 1;l <= 4;l++) printf("%d ",cnt[l]); cout << endl;
     69 //        printf("#%d color_res: ",u); for(int l = 0;l <= mx;l++) printf("%d ",result[l]); cout << endl;
     70 //        printf("#%d mx: %d
    ",u,mx);
     71         
     72     }if(son[u]) dsu(son[u],u);
     73     for(int i = 0;i < G[u].size();i++){
     74         if(G[u][i] == fa || G[u][i] == son[u]) continue;
     75         Add(G[u][i],mx);
     76     }
     77 //    cout << "Now B" << endl;
     78 //    printf("#%d color_cnt: ",u); for(int i = 1;i <= 4;i++) printf("%d ",cnt[i]); cout << endl;
     79 //    printf("#%d color_res: ",u); for(int i = 0;i <= mx;i++) printf("%d ",result[i]); cout << endl;
     80 //    printf("#%d mx: %d
    ",u,mx);
     81     result[cnt[color[u]]] -= color[u];
     82     cnt[color[u]]++;
     83     result[cnt[color[u]]] += color[u];
     84     
     85     mx = max(cnt[color[u]],mx);
     86     while(!result[mx] && mx) mx--; // 这一句加与不加都能AC,但我还是加上去= =保险起见,如果有人研究出原因请告诉我呀qwq
     87     ans[u] = max(result[mx],0LL);
     88 //    cout << "Now C" << endl;
     89 //    printf("#%d color_cnt: ",u); for(int i = 1;i <= n;i++) printf("%d ",cnt[i]); cout << endl;
     90 //    printf("#%d color_res: ",u); for(int i = 0;i <= n;i++) printf("%d ",result[i]); cout << endl;
     91 //    printf("#%d mx: %d
    ",u,mx);
     92 }
     93 
     94 int main(){
     95     
     96 //    freopen("1.in","r",stdin);
     97     
     98     scanf("%d",&n);
     99     
    100     for(int i = 1;i <= n;i++)
    101         scanf("%d",&color[i]);
    102         
    103     for(int i = 1;i < n;i++){
    104         int u,v; scanf("%d%d",&u,&v);
    105         G[u].push_back(v); G[v].push_back(u);
    106     }
    107     
    108     dfs(1,1); 
    109     
    110 //    for(int i = 1;i <= n;i++) printf("#%d: %d ~ %d
    ",i,L[i],R[i]);
    111     
    112     dsu(1,1);
    113     
    114     for(int i = 1;i <= n;i++) if(i == 1) printf("%I64d",ans[i]); else printf("% I64d",ans[i]);
    115     
    116     return 0;
    117 }
    600E - DSUoT模板题qwq 因为某些原因CF没有公开数据,需要自行对拍
  • 相关阅读:
    pythonGUI-wxpython
    [转]谈谈 Mifare Classic 破解
    python-optparse模块给脚本增加参数选项
    [笔记]python
    mac伪装工具macchanger
    mitmproxy
    yersinia的DHCP池耗尽断网攻击
    kalilinux工具中文在线
    MSF内网渗透 扫描模块
    渗透测试的一些总结
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7728491.html
Copyright © 2011-2022 走看看