• 题解报告——离家出走


    离家出走

    时间限制: 2000 ms         内存限制: 262144 KB

    【题目描述】

    企鹅豆豆考试爆零了,心态爆炸的他准备离家出走。

    贫穷的企鹅国有 N 座城市,一开始城市之间没有道路连接不能通行。随着时间推移,一些道路逐渐建立。但由于国家财力实在不足,所以随时随地任意两座城市最多只有一条路径可以互相到达。

    每次豆豆考试爆炸,他都想从考场里跑到离考场最远的一个城市去。当然豆豆每次都会想知道,最远的且可以到达的城市离考场所在城市有多远?

    奇妙的事情是,企鹅国的每一条道路长度都是 1。

    【输入】

    第一行一个整数 type,表示数据类型。

    接下来第二行两个整数 N,Q,表示城市个数和事件个数。

    接下来 Q 行,先读入一个整数 op,表示事件类型。

    如果 op=1,那么接着有两个整数 u,v,表示城市 u 和城市 v 之间建立了一条新的道路。

    如果 op=2,那么接着有一个整数 u,表示这次考试的考场在城市 u,豆豆想知道最远的城市离考场有多远。

    如果 type=1,令上一次 op=2 时的答案为 lastans,那么对于输入的每一个 u 或者 v 都需要异或上 lastans。(lastans 初始为 0。)

    如果 type=0,那么不需要进行其余额外操作。

    【输出】

    对于每次 op=2 的询问,输出一行一个整数表示离考场最远的城市距离考场的距离。

    【输入样例】

    0
    5 10
    1 4 5
    2 3
    2 5
    2 1
    1 5 3
    1 1 4
    2 3
    2 5
    1 5 2
    2 1

    【输出样例】

    0
    1 
    0
    3
    2
    3

    【提示】

    对于 20%的输入数据:N≤5000,Q≤10000。

    对于 50%的输入数据:N≤100000,Q≤200000。

    对于另外 20%的输入数据:type=0。

    对 100%的输入数据:N≤300000,Q≤500000,道路的修建会满足,随时随地图中不存在环。


    【思路分析】

    暑假集训考试,成功实现暴力操标算,我的暴力查询得到了buff加成,成功超越去写标算的同学,当然还是没有凯爷的标算快(谁叫人家是集训队的。。。),听说标算要维护树的直径和LCA(复杂度应该是nlogn^2)

    我们很容易发现这道题的是一颗树,每次连边就是树的合并,当然可以用LCT大力搞一搞(复杂度nlogn),然而考试时蒟蒻的我根本打不出LCT,所以我们想可以进行子树的合并,不难想到用启发式合并去优化,启发式合并就是选择较小的子树接到大的子树上,然后dfs更新较小树的信息(深度,树根,父亲)。然后在向上更新较大子树的子树大小(只用更新连接点的祖先),我们发现因为每次选择较小的更新,大小不会超过一半,所以每个节点的更新次数不会超过logn次,然后就很优秀了(然而考场上没想到怎么证复杂度就去写了,真的虚。。。)

    对于查询操作,我们维护两个信息,一个是dis[i] 记录节点i的子树中最深叶子的深度,还有一个dep[i]记录每个节点的深度,查询一个点时就向上跳father就可以了。


    【代码实现】

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<algorithm>
     4 using namespace std;
     5 void read(int &v)
     6 {
     7     int f;char ch;
     8     while(!isdigit(ch=getchar())&&ch!='-'); ch=='-'?(v=0,f=-1):(v=ch-'0',f=1);
     9     while(isdigit(ch=getchar())) v=v*10+ch-'0';v=v*f;
    10 }
    11 const int N=3e5+5;
    12 struct sd{
    13     int next,to;
    14 }edge[N<<1];
    15 int head[N],fa[N],dis[N],root[N],siz[N],dep[N],n,cnt,lastans,q;
    16 void add_edge(int x,int y)
    17 {
    18     edge[++cnt].to=y;
    19     edge[cnt].next=head[x];
    20     head[x]=cnt;
    21 }
    22 void dfs(int v,int ff,int rt)
    23 {
    24     fa[v]=ff,root[v]=rt,siz[v]=1,dep[v]=dep[ff]+1,dis[v]=0;
    25     for(int i=head[v];i;i=edge[i].next)
    26     {
    27         int to=edge[i].to;
    28         if(to!=ff)
    29         {
    30             dfs(to,v,rt);
    31             siz[v]+=siz[to];
    32             dis[v]=max(dis[v],dis[to]+1);
    33         }
    34     }
    35 }
    36 void update(int v,int son,int sss)
    37 {
    38     siz[v]+=sss,dis[v]=max(dis[v],dis[son]+1);
    39     if(root[v]==v) return;
    40     update(fa[v],v,sss);
    41 }
    42 void merge(int a,int b)
    43 {
    44     add_edge(a,b),add_edge(b,a);
    45     dfs(b,a,root[a]);
    46     siz[a]+=siz[b],dis[a]=max(dis[a],dis[b]+1);
    47     if(root[a]!=a) update(fa[a],a,siz[b]);
    48 }
    49 void ask(int v,int goal)
    50 {
    51     if(root[v]==v) return;
    52     int ff=fa[v];bool gg=1;
    53     for(int i=head[ff];i;i=edge[i].next)
    54     {
    55         int to=edge[i].to;
    56         if(to!=fa[ff]&&to!=v)
    57         {
    58             gg=0;
    59             lastans=max(lastans,dep[goal]-dep[ff]+dis[to]+1);
    60         }
    61     }
    62     if(gg) lastans=max(lastans,dep[goal]-dep[ff]);
    63     ask(ff,goal);
    64 }
    65 int main()
    66 {
    67     //freopen("away.in","r",stdin);freopen("away.out","w",stdout);
    68     int type,opt,a,b;
    69     read(type),read(n),read(q);
    70     for(int i=1;i<=n;i++) root[i]=i,fa[i]=i,siz[i]=1,dep[i]=1;
    71     while(q--)
    72     {
    73         read(opt);
    74         if(opt==1)
    75         {
    76             read(a),read(b);
    77             if(type) a=a^lastans,b=b^lastans;
    78             if(siz[root[a]]<siz[root[b]]) swap(a,b);
    79             merge(a,b);
    80         }
    81         else
    82         {
    83             read(a);
    84             if(type) a=a^lastans;
    85             lastans=0;
    86             ask(a,a);
    87             lastans=max(lastans,dis[a]);
    88             printf("%d
    ",lastans);
    89         }
    90     }
    91     return 0;
    92 }
  • 相关阅读:
    Selenium学习:鼠标事件
    Selenium学习:新窗口打开链接,并定位到新窗口
    Selenium学习:get_attribute()方法获取列表元素信息
    Java 基础(接口二)
    Java 基础(接口一)
    Java 练习(模板方法设计模式TemplateMethod)
    Java 基础(多态的应用:模板方法设计模式TemplateMethod)
    Java 基础(抽象类的匿名子类)
    Java 练习(抽象类与抽象方法)
    Java 基础( final 关键字)
  • 原文地址:https://www.cnblogs.com/genius777/p/9347912.html
Copyright © 2020-2023  润新知