• 洛谷 P2195 HXY造公园


    题目描述

    现在有一个现成的公园,有n个休息点和m条双向边连接两个休息点。众所周知,HXY是一个SXBK的强迫症患者,所以她打算施展魔法来改造公园并即时了解改造情况。她可以进行以下两种操作:

    1、对某个休息点x,查询公园中所有经过该休息点的路径中的最长路径。

    2、对于两个休息点x、y,如果x,y已经可以互相到达则忽略此次操作。否则,在x可到达的所有休息点和y可到达的所有休息点(包括x,y自身)分别选择一个休息点,然后在这两个休息点之间连一条边,并且这个选择应该满足对于连接后的公园,x和y所在的区域(即x,y可达到的所有休息点和边组成的集合)中的最长路径的长度最小。

    HXY打算进行q个操作,请你回答她的对于公园情况的询问(操作1)或者执行她的操作(操作2)。

    注:所有边的长度皆为1。保证不存在环。最长路径定义为:对于点v1,v2......vk,如果对于其中任意的vi和vi+1(1<=i<=k-1),都有边相连接,那么vj(1<=j<=k)所在区域的最长路径就是k-1。

    输入输出格式

    输入格式:

     

    第一行,三个正整数,分别为n,m,q。

    接下来的m行,每一行有两个正整数xi,yi,表示xi和yi有一条双向边相连。

    再接下来的q行,每一行表示一个操作。

    若该行第一个数为1,则表示操作1,之后还有一个正整数xi,表示要查询的休息点。

    若该行第一个数为2,则表示操作2,之后还有两个正整数xi,yi,表示需要执行操作的两个休息点。

     

    输出格式:

     

    输出行数为操作1的个数。

    每行输出对于操作1询问的回答。

     

    输入输出样例

    输入样例#1: 复制
    6 0 6
    2 1 2
    2 3 4
    2 5 6
    2 3 2
    2 5 3
    1 1
    输出样例#1: 复制
    4
    

    说明

    数据范围:

    对于10%的数据,只存在操作1。

    对于30%的数据,1<=m<n<=20,1<=q<=5。

    对于60%的数据,1<=m<n<=2000,1<=q<=1000。

    对于100%的数据,1<=m<n<=3*10^5,1<=q<=3*10^5。

    思路:总的来说,用并查集做辅助工具,然后预处理出最长链,题目并不难。但是还存在一个问题:

      那就是在一棵树中,经过这个点的所有的路径中最长的为什么就是这棵树的直径。题解是这么写的,但是划拉了一下,不是很明白为什么。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 2010
    using namespace std;
    int n,m,q,tot;
    int fa[MAXN],dis[MAXN];
    int sum1[MAXN],sum2[MAXN],dad[MAXN];
    int mid[MAXN],lcnt[MAXN],rcnt[MAXN];
    int to[MAXN*2],net[MAXN*2],head[MAXN];
    int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
    void add(int u,int v){
        to[++tot]=v;net[tot]=head[u];head[u]=tot;
        to[++tot]=u;net[tot]=head[v];head[v]=tot;
    }
    void dfs(int now){
        for(int i=head[now];i;i=net[i])
            if(dis[to[i]]==-1){
                dis[to[i]]=dis[now]+1;
                dfs(to[i]);
            }
    }
    void dfs1(int now){
        for(int i=head[now];i;i=net[i])
            if(dad[now]!=to[i]){
                dad[to[i]]=now;
                sum1[to[i]]=sum1[now]+1;
                dfs1(to[i]);
            }
    }
    void dfs2(int now){
        for(int i=head[now];i;i=net[i])
            if(dad[now]!=to[i]){
                dad[to[i]]=now;
                sum2[to[i]]=sum2[now]+1;
                dfs2(to[i]);
            }
    }
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)    fa[i]=i;
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
             add(x,y);int dx=find(x),dy=find(y);
             if(dx==dy)    continue;
             fa[dy]=dx;
        }
        for(int i=1;i<=n;i++)
            if(find(i)==i){
                int src;src=i;
                memset(dis,-1,sizeof(dis));
                dis[src]=0;dfs(src);
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                memset(dis,-1,sizeof(dis));
                dis[src]=0;dfs(src);lcnt[i]=src;
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                rcnt[i]=src;int minn=0x7f7f7f7f;
                dfs1(src);memset(dad,0,sizeof(dad));
                dfs2(src);memset(dad,0,sizeof(dad));
                for(int j=1;j<=n;j++)
                    if(find(j)==i){
                        int len=abs(sum1[j]-sum2[j]);
                        if(len<minn){ minn=len;mid[i]=j; }
                    }
                memset(sum1,0,sizeof(sum1));
                memset(sum2,0,sizeof(sum2));
            }
        for(int i=1;i<=q;i++){
            int opt,x,y;
             scanf("%d%d",&opt,&x);
            if(opt==1){
                memset(dis,-1,sizeof(dis));
                dis[x]=0;dfs(x);int dx=find(x);
                int ans=max(dis[lcnt[dx]],dis[rcnt[dx]]);
                int maxn=0,ops;
                if(dis[lcnt[dx]]>dis[rcnt[dx]])    ops=lcnt[dx];
                else ops=rcnt[dx];
                dfs1(lcnt[dx]);memset(dad,0,sizeof(dad));
                dfs2(rcnt[dx]);memset(dad,0,sizeof(dad));
                for(int j=1;j<=n;j++)
                    if(dx==find(j)&&i!=j&&j!=ops&&(sum1[j]-sum2[j]==sum1[x]-sum2[x]||j==lcnt[dx]||j==rcnt[dx]))
                        maxn=max(maxn,dis[j]);
                cout<<ans+maxn<<endl;
                memset(sum1,0,sizeof(sum1));
                memset(sum2,0,sizeof(sum2));
             }
            else if(opt==2){
                 scanf("%d",&y);
                 int dx=find(x),dy=find(y);
                 if(dx==dy)    continue;fa[dy]=dx;
                 add(mid[dx],mid[dy]);
                 memset(dis,-1,sizeof(dis));
                 int src;src=x;
                dis[src]=0;dfs(src);
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                memset(dis,-1,sizeof(dis));
                dis[src]=0;dfs(src);lcnt[dx]=src;
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                rcnt[dx]=src;int minn=0x7f7f7f7f;
                dfs1(lcnt[dx]);memset(dad,0,sizeof(dad));
                dfs2(rcnt[dx]);memset(dad,0,sizeof(dad));
                for(int j=1;j<=n;j++)
                    if(find(j)==dx){
                        int len=abs(sum1[j]-sum2[j]);
                        if(len<minn){ minn=len;mid[dx]=j; }
                    }
                memset(sum1,0,sizeof(sum1));
                memset(sum2,0,sizeof(sum2));
            }
        }
    }
    /*
    6 0 6
    2 1 2
    2 3 4
    2 5 6
    2 3 2
    2 5 3
    1 1
    */
    不知道为什么wa了3个点的30分暴力

    70分的dfs:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 300010
    using namespace std;
    int n,m,q,tot;
    int fa[MAXN],dis[MAXN],len[MAXN];
    int sum1[MAXN],sum2[MAXN],dad[MAXN];
    int mid[MAXN],lcnt[MAXN],rcnt[MAXN];
    int to[MAXN*2],net[MAXN*2],head[MAXN];
    int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
    void add(int u,int v){
        to[++tot]=v;net[tot]=head[u];head[u]=tot;
        to[++tot]=u;net[tot]=head[v];head[v]=tot;
    }
    void dfs(int now){
        for(int i=head[now];i;i=net[i])
            if(dis[to[i]]==-1){
                dis[to[i]]=dis[now]+1;
                dfs(to[i]);
            }
    }
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)    fa[i]=i;
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
             add(x,y);int dx=find(x),dy=find(y);
             if(dx==dy)    continue;    fa[dy]=dx;
        }
        
        for(int i=1;i<=n;i++)
            if(find(i)==i){
                int src;src=i;
                
                memset(dis,-1,sizeof(dis));
                dis[src]=0;dfs(src);
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                lcnt[i]=src;
                    
                memset(dis,-1,sizeof(dis));
                dis[src]=0;dfs(src);
                for(int j=1;j<=n;j++)
                    if(dis[j]>dis[src])    src=j;
                rcnt[i]=src;len[i]=dis[src];
            }
        for(int i=1;i<=q;i++){
            int opt,x,y;
             scanf("%d%d",&opt,&x);
            if(opt==1)    cout<<len[find(x)]<<endl;
            else if(opt==2){
                 scanf("%d",&y);
                 int dx=find(x),dy=find(y);
                 if(dx==dy)    continue;fa[dy]=dx;
                int a=len[dx],b=len[dy];
                len[dx]=(len[dx]+1)/2+(len[dy]+1)/2+1;
                if(len[dx]<a)    len[dx]=a;
                if(len[dx]<b)    len[dx]=b;
            }
        }
    }
    /*
    6 0 6
    2 1 2
    2 3 4
    2 5 6
    2 3 2
    2 5 3
    1 1
    */

    因为是RE和TLE,所以说,我怀疑是因为树太长了,所以爆栈了。

    改成bfs就能AC了,但是我改了改,没改出来,所以就不改了。但是思路是正确的。

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 300010
    using namespace std;
    int n,m,q,tot;
    struct nond{ int pos,dis; };
    int fa[MAXN],dis[MAXN],len[MAXN];
    int sum1[MAXN],sum2[MAXN],dad[MAXN];
    int mid[MAXN],lcnt[MAXN],rcnt[MAXN];
    int to[MAXN*2],net[MAXN*2],head[MAXN];
    int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
    void add(int u,int v){
        to[++tot]=v;net[tot]=head[u];head[u]=tot;
        to[++tot]=u;net[tot]=head[v];head[v]=tot;
    }
    int bfs(int x){
        queue<nond>que;
        nond tmp;tmp.pos=x;tmp.dis=0;
        que.push(tmp);int maxn=0,opt=x;
        while(!que.empty()){
            nond now=que.front();que.pop();
            for(int i=head[now.pos];i;i=net[i]){
                nond tmx;tmx.pos=to[i];tmx.dis=now.dis+1;
                que.push(tmx);
                if(tmx.dis>maxn){ maxn=tmx.dis;opt=to[i]; }
            }
        }
        while(!que.empty())    que.pop();
        tmp.pos=opt;tmp.dis=0;
        que.push(tmp);
        while(!que.empty()){
            nond now=que.front();que.pop();
            for(int i=head[now.pos];i;i=net[i]){
                nond tmx;tmx.pos=to[i];tmx.dis=now.dis+1;
                que.push(tmx);
                if(tmx.dis>maxn){ maxn=tmx.dis; }
            }
        }
        return maxn;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)    fa[i]=i;
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
             add(x,y);int dx=find(x),dy=find(y);
             if(dx==dy)    continue;    fa[dy]=dx;
        }
        for(int i=1;i<=n;i++)
            if(find(i)==i)    len[i]=bfs(i);
        for(int i=1;i<=q;i++){
            int opt,x,y;
             scanf("%d%d",&opt,&x);
            if(opt==1)    cout<<len[find(x)]<<endl;
            else if(opt==2){
                 scanf("%d",&y);
                 int dx=find(x),dy=find(y);
                 if(dx==dy)    continue;fa[dy]=dx;
                int a=len[dx],b=len[dy];
                len[dx]=(len[dx]+1)/2+(len[dy]+1)/2+1;
                if(len[dx]<a)    len[dx]=a;
                if(len[dx]<b)    len[dx]=b;
            }
        }
    }
    /*
    6 0 6
    2 1 2
    2 3 4
    2 5 6
    2 3 2
    2 5 3
    1 1
    */
    改错的10分的代码
    细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。 雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。
  • 相关阅读:
    20155207 2016-2017-2《Java程序设计》课程总结
    Mycp补交作业
    20155207 实验五 网络编程与安全
    20155206 随堂作业
    20155206 《Java程序设计》实验三实验报告
    20155206 2016-2017-2 《Java程序设计》第十周学习总结
    20155206 《JAVA程序设计》实验二(JAVA面向对象程序设计)实验报告
    20155206 2016-2017-2 《Java程序设计》第9周学习总结
    20155206 2016-2017-2 《Java程序设计》第8周学习总结
    20155206 实验一《Java开发环境的熟悉》实验报告
  • 原文地址:https://www.cnblogs.com/cangT-Tlan/p/8849023.html
Copyright © 2020-2023  润新知