bzoj5192 [Usaco2018 Feb]New Barns

http://www.elijahqi.win/2018/03/06/bzoj5192-usaco2018-febnew-barns/
Description
FarmerJohn注意到他的奶牛们如果被关得太紧就容易吵架,所以他想开放一些新的牛棚来分散她们。每当FJ建造一
个新牛棚的时候,他会将这个牛棚用至多一条双向道路与一个现有的牛棚连接起来。为了确保他的奶牛们足够分散
,他有时想要确定从某个特定的牛棚出发,到它能够到达的最远的牛棚的距离(两个牛棚之间的距离等于从一个牛
棚出发到另一个之间必须经过的道路条数)。FJ总共会给出Q(1≤Q≤10^5)次请求,每个请求都是“建造”和“
距离”之一。对于一个建造请求,FJ建造一个牛棚,并将其与至多一个现有的牛棚连接起来。对于一个距离请求,
FJ向你询问从某个特定的牛棚通过一些道路到离它最远的牛棚的距离。保证询问的牛棚已经被建造。请帮助FJ响应
所有的请求。

Input
第一行包含一个整数Q
以下Q行,每行包含一个请求。每个请求的格式都是“B p”或是“Q k”
分别告诉你建造一个牛棚并与牛棚p连接,或是根据定义求从牛棚k出发最远的距离。
如果p=-1,则新的牛棚不会与其他牛棚连接。
否则,p是一个已经建造的牛棚的编号。
牛棚编号从1开始,所以第一个被建造的谷仓是1号谷仓,第二个是2号谷仓,以此类推。

Output
对于每个距离请求输出一行。注意一个没有连接到其他牛棚的牛棚的最远距离为0

Sample Input
7

B -1

Q 1

B 1

B 2

Q 3

B 2

Q 2
Sample Output
0

2

1

输入样例对应下面的牛棚网:

(1)

\   

 (2)---(4)

/

(3)

对于请求1,我们建造牛棚1。对于请求2,我们询问从1出发到最远连接的牛棚的距离。由于牛棚1没有与其他牛棚

连接,所以回答是0。对于请求3,我们建造牛棚2并将其与牛棚1连接。对于请求4,我们建造牛棚3并将其与牛棚2

连接。对于请求5,我们询问从3出发到最远连接的牛棚的距离。在这时,最远的是牛棚1,距离为2单位。对于请求

6,我们建造牛棚4并将其与牛棚2连接。对于请求7,我们询问从2出发到最远连接的牛棚的距离。所有其他三个牛

棚1,3,4都与2相距相同的距离1,所以这就是我们的回答。
题意:每次添加一个点 求距离这个点最远的点是谁
注意有可能存在 这些点并不连通的情况
那么题目没有强制在线 首先我们离线进来把整个树建好 那么 对于这棵树而言我相当于先点分一下 然后每次询问的时候就是在我点分树父节点里找一个不是来自我的最大值加上我到x的距离即可 那该怎么做 只需要维护几个值即可 在这个点分树上维护到我这个分治重心的最远点是谁 还有最远点属于的子树 还有不包含在最远点子树里的次远点 那么每次新建一个节点相当于点分树上这个节点我可以走了 那么就直接做就好了 注意询问的时候要判断分治中心是否已经可以走 复杂度n*log(n)

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 110000
#define pa pair<int,int>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
struct node{
    int y,next;
}data[N<<1];
struct node1{
    int x,op;
}qr[N];
struct node2{
    int mx1,mxid,mx2;
}tree[N];
bool flag[N],visit[N];
int dep[N],num,h[N],n,m,sum,root,size[N];
vector<pa> par[N];
inline void insert1(int x,int y){
    data[++num].y=y;data[num].next=h[x];h[x]=num;
    data[++num].y=x;data[num].next=h[y];h[y]=num;
}
inline void dfs(int x,int fa){
    size[x]=1;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa) continue;dfs(y,x);size[x]+=size[y];
    }
}
inline void dfs1(int x,int f,int bl){
    par[x].push_back(make_pair(dep[x],bl));
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (visit[y]||y==f) continue;
        dep[y]=dep[x]+1;dfs1(y,x,bl);
    }
}
int f[N];
inline void get_root(int x,int fa){
    f[x]=0;size[x]=1;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa||visit[y]) continue;
        get_root(y,x);size[x]+=size[y];f[x]=max(f[x],size[y]);
    }f[x]=max(f[x],sum-size[x]);
    if (f[root]>f[x]) root=x;
}int fa[N];
inline void solve(int x){
    visit[x]=1;int sum1=sum;dep[x]=0;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (visit[y]) continue;
        dep[y]=1;dfs1(y,x,y);
    }
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (visit[y]) continue;
        if(size[y]>size[x]) sum=sum1-size[x];else sum=size[y];
        root=0;get_root(y,x);fa[root]=x;solve(root);
    }
}
inline void change(int x){
    int xx=fa[x];
    for (int i=par[x].size()-1;~i;--i){

        int d=par[x][i].first,bl=par[x][i].second;
        //printf("%d %d\n",xx,d);
        //printf("%d %d %d\n",tree[xx].mx1,tree[xx].mxid,tree[xx].mx2);
        if (d>=tree[xx].mx1){
            if (bl!=tree[xx].mxid) tree[xx].mx2=tree[xx].mx1;
            tree[xx].mx1=d;tree[xx].mxid=bl;
        }else if (bl!=tree[xx].mxid&&d>tree[xx].mx2) tree[xx].mx2=d;
        xx=fa[xx];
    }
}
inline int query(int x){
    int tmp=tree[x].mx1,xx=fa[x];
    for (int i=par[x].size()-1;~i;--i){
        int d=par[x][i].first,bl=par[x][i].second;
        //printf("%d\n",tmp);
        if (flag[xx]){
    //  printf("%d %d\n",xx,d);
            if(bl!=tree[xx].mxid) tmp=max(tmp,tree[xx].mx1+d);
            else tmp=max(tmp,tree[xx].mx2+d);
        }xx=fa[xx];
    }return tmp;
}
int main(){
    freopen("bzoj5192.in","r",stdin);
    freopen("bzoj5192.out","w",stdout);
    m=read();f[0]=inf;
    for (int i=1;i<=m;++i){
        char ch=gc();while(ch!='B'&&ch!='Q') ch=gc();int x=read();
        if (ch=='B') {++n;if (x==-1) flag[n]=1;else insert1(n,x);qr[i].x=n;qr[i].op=1;}
        else qr[i].op=2,qr[i].x=x;
    }
    for (int i=1;i<=n;++i){
        if (!flag[i]) continue;dfs(i,i);sum=size[i];root=0;get_root(i,i);solve(root);
    }memset(flag,0,sizeof(flag));
    /*for (int i=1;i<=13;++i){
        printf("%d %d\n",qr[i].x,qr[i].op);
    }*/
    for (int i=1;i<=m;++i){
        if (qr[i].op==1) change(qr[i].x),flag[qr[i].x]=1;
        else printf("%d\n",query(qr[i].x));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值