zoukankan      html  css  js  c++  java
  • [CF1009F] Dominant Indices (+dsu on tree详解)

    这道题用到了dsu(Disjoint Set Union) on tree,树上启发式合并。

    先看了CF的官方英文题解,又看了看zwz大佬的题解,差不多理解了dsu on tree的算法。

    但是时间复杂度有点玄学,问了一下zwz大佬才懂了为什么是nlogn。

    题目传送门

    先考虑暴力n^2的算法。

    显然对于某个点,搜一遍它的子树,就能得到这个点的答案。这一步是O(n)的。

    每个点都这么搞一遍,就是O(n^2)的暴力做法。

    但是这个暴力做法有一点不足,子节点的答案没有应用到父节点的计算中,白白浪费时间重算一遍。

    考虑优化,类似树链剖分,找出子树最大的儿子称作重儿子,把它的答案留着,这样计算父节点时就不用搜这个重儿子了。

    显然保留子树最大的儿子的信息,能够节约最多的时间。

    但是如果计算完重儿子的答案,保留了信息,再计算别的儿子的答案,已保留的信息会对当前的计算产生干扰。

    所以我们先计算轻儿子,最后计算重儿子。

    如果是轻儿子,更新答案计算后,暴力再改回去。

    如果是重儿子,就留着。

    计算完所有儿子的答案后,最后计算当前点。

    只需要加上轻儿子的信息就好。重儿子的信息已经留着了,不用再加了。

    下面是zwz大佬对于dsu on tree时间复杂度的证明:

    每个节点只会在祖先节点的计算中被搜到。

    而且只有它到它父亲是轻边的时候才会搜一遍。

    所以每个点的计算次数是它到根的轻边数量,为logn。

    所以总时间复杂度是nlogn。

    感觉dsu也是挺暴力的,每次留一个,居然时间上优化了很多。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 #define MAXN 1000005
      6 using namespace std;
      7 
      8 int n;
      9 int hd[MAXN],nx[MAXN<<1],to[MAXN<<1],ec;
     10 int dep[MAXN],sz[MAXN],ans[MAXN],cnt[MAXN];
     11 
     12 void edge(int af,int at)
     13 {
     14     to[++ec]=at;
     15     nx[ec]=hd[af];
     16     hd[af]=ec;
     17 }
     18 
     19 void pre(int p,int fa)
     20 {
     21     sz[p]=1;
     22     dep[p]=dep[fa]+1;
     23     for(int i=hd[p];i;i=nx[i])
     24     {
     25         if(to[i]==fa)continue;
     26         pre(to[i],p);
     27         sz[p]+=sz[to[i]];
     28     }
     29 }
     30 
     31 struct data
     32 {
     33     int d,v;
     34     friend bool operator<(data q,data w)
     35     {
     36         if(q.v==w.v)return q.d>w.d;
     37         return q.v<w.v;
     38     }
     39 };
     40 
     41 priority_queue<data>qq;
     42 
     43 void add(int p,int fa)
     44 {
     45     cnt[dep[p]]++;
     46     data neo={dep[p],cnt[dep[p]]};
     47     qq.push(neo);
     48     for(int i=hd[p];i;i=nx[i])if(to[i]!=fa)add(to[i],p);
     49 }
     50 
     51 void del(int p,int fa)
     52 {
     53     cnt[dep[p]]--;
     54     for(int i=hd[p];i;i=nx[i])if(to[i]!=fa)del(to[i],p);
     55 }
     56 
     57 void dfs(int p,int fa,int stay)
     58 {
     59     int son=0,mx=-1;
     60     for(int i=hd[p];i;i=nx[i])
     61     {
     62         if(to[i]==fa)continue;
     63         if(mx<sz[to[i]])mx=sz[to[i]],son=to[i];
     64     }
     65     for(int i=hd[p];i;i=nx[i])
     66     {
     67         if(to[i]==fa||to[i]==son)continue;
     68         dfs(to[i],p,0);
     69     }
     70     if(son)dfs(son,p,1);
     71     for(int i=hd[p];i;i=nx[i])
     72     {
     73         if(to[i]==fa||to[i]==son)continue;
     74         add(to[i],p);
     75     }
     76     cnt[dep[p]]++;
     77     data neo={dep[p],cnt[dep[p]]};
     78     qq.push(neo);
     79     ans[p]=qq.top().d-dep[p];
     80     if(!stay)
     81     {
     82         del(p,fa);
     83         while(!qq.empty())qq.pop();
     84     }
     85 }
     86 
     87 int main()
     88 {
     89     scanf("%d",&n);
     90     for(int i=1;i<n;i++)
     91     {
     92         int x,y;
     93         scanf("%d%d",&x,&y);
     94         edge(x,y);
     95         edge(y,x);
     96     }
     97     pre(1,0);
     98     dfs(1,0,1);
     99     for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    100     return 0;
    101 }
    CF1009F Dominant Indices

    P.S. 调试的时候改小了数组,提交的时候忘改回去了......改回去之后直接A掉了......有点桑心哈哈哈

  • 相关阅读:
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 2 Messags Partterns
    WPF动态更改Image控件图片路径
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 1
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 4 Handling Errors and ETERM
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 3 Messags Partterns
    Visual Studio 2008 测试项目无法正常显示解决办法
    Ext.NET控件介绍—Form控件
    ThoughtWorks(中国)程序员读书雷达
    Ext.net 中日期格式的计算
    Sql 分割 键值对字符串 得到某值对应的名称
  • 原文地址:https://www.cnblogs.com/cervusy/p/9556766.html
Copyright © 2011-2022 走看看