zoukankan      html  css  js  c++  java
  • 洛谷 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分的代码
    细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。 雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。
  • 相关阅读:
    第八章 多线程编程
    Linked List Cycle II
    Swap Nodes in Pairs
    Container With Most Water
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock II
    Linked List Cycle
    4Sum
    3Sum
    Integer to Roman
  • 原文地址:https://www.cnblogs.com/cangT-Tlan/p/8849023.html
Copyright © 2011-2022 走看看