• 【杂题】10.7爬树


    是该来道小清新思考题醒醒脑的时候了

    题目大意

    一颗$n$个点初全为白色的树,有$q$个操作:

    1. 将指定点$x$变为黑色
    2. 查询点$x$到所有黑色点路径上,编号最小的点

    $n,q le 10^6$


    题目分析

    $O(nlog n)$的做法略过不谈

    首先把第一个黑点$rt$作为根节点,然后预处理一个$f_i$表示$i$点到$rt$路径上最小的节点作为初始答案。

    接下去考虑每一个黑点$i$会对其他点$j$造成什么影响。

    可以分为如上三种情况讨论。

    $ exttt{j}$在$ exttt{i}$的子树内:$i$只会贡献$icdots j$的路径,而这一部分已经被包括在$f_j$内了。

    $ exttt{j}$在$ exttt{i}$到$ exttt{rt}$的路径上:虽然只有$i cdots j$路径被贡献,但由于$jcdots rt$的路径本身也被计入$f_i$,因此可以视作贡献了$f_j$.

    $ exttt{i}$到$ exttt{j}$的路径跨越$ exttt{rt}$:$i cdots j$的路径可以拆成$icdots rt$和$jcdots rt$,也就是说$j$对$i$有$f_j$的贡献。

    综上讨论可知,只要加进来一个黑点$i$,它就会对其他所有点产生$f_i$的贡献!

    这比$O(nlog n)$的思路清新得多。

    也算是一个警醒,想题目还是要逐层冷静分析,不要太浮躁。

     1 #include<bits/stdc++.h>
     2 const int maxn = 1000035;
     3 const int maxm = 2000035;
     4 
     5 int n,q,rt,ans,cnt,f[maxn];
     6 int edgeTot,head[maxn],nxt[maxm],edges[maxm];
     7 
     8 int read()
     9 {
    10     char ch = getchar();
    11     int num = 0, fl = 1;
    12     for (; !isdigit(ch); ch=getchar())
    13         if (ch=='-') fl = -1;
    14     for (; isdigit(ch); ch=getchar())
    15         num = (num<<1)+(num<<3)+ch-48;
    16     return num*fl;
    17 }
    18 void addedge(int u, int v)
    19 {
    20     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
    21     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
    22 }
    23 void dfs(int x, int fa, int c)
    24 {
    25     f[x] = c;
    26     for (int i=head[x]; i!=-1; i=nxt[i])
    27         if (edges[i]!=fa) dfs(edges[i], x, std::min(c, edges[i]));
    28 }
    29 void write(int x){if (x/10) write(x/10);putchar(x%10+'0');}
    30 int main()
    31 {
    32     memset(f, 0x3f3f3f3f, sizeof f);
    33     memset(head, -1, sizeof head);
    34     n = read(), q = read()-1, cnt = 0x3f3f3f3f;
    35     for (int i=1; i<n; i++) addedge(read(), read());
    36     rt = read(), rt = read()+1, dfs(rt, 0, rt);
    37     for (int opt,pos; q; --q)
    38     {
    39         opt = read(), pos = (read()+ans)%n+1;
    40         if (opt==1) cnt = std::min(cnt, f[pos]);
    41         else ans = std::min(f[pos], cnt), write(ans), putchar('
    ');
    42     }
    43     return 0;
    44 } 

    END

  • 相关阅读:
    自动换行的两种代码(C#)
    C#的SubString(int start,int end);
    php数组添加元素的方法
    php通过生成动态变量(变量名中还有变量)
    php定义空的数组
    php的$GLOBALS例子
    WINCRIS的使用
    java的PreparedStatement中使用like时的问题
    php发送get请求
    在HTML中使用object和embed标签插入视频
  • 原文地址:https://www.cnblogs.com/antiquality/p/11630554.html
Copyright © 2020-2023  润新知