AtCoder Grand Contest 002 D - Stamp Rally

Description

We have an undirected graph with N vertices and M edges. The vertices are numbered 1 through N, and the edges are numbered 1 through M. Edge i connects vertices ai and bi. The graph is connected.
On this graph, Q pairs of brothers are participating in an activity called Stamp Rally. The Stamp Rally for the i-th pair will be as follows:

One brother starts from vertex xi, and the other starts from vertex yi.
The two explore the graph along the edges to visit zi vertices in total, including the starting vertices. Here, a vertex is counted only once, even if it is visited multiple times, or visited by both brothers.
The score is defined as the largest index of the edges traversed by either of them. Their objective is to minimize this value.

Find the minimum possible score for each pair.

Solution

这题一个直接的思路就是二分答案,加边之后判连通块大小
由于有 \(Q\) 组询问,考虑整体二分
注意到这一题中不仅 \([L,mid]\) 之间的边有贡献, \([1,mid]\) 之间的边也有贡献
如果 \(dfs\) 处理的话,复杂度就不对了
考虑 \(bfs\) 序整体二分:
我们每一次都需要把 \([1,mid]\) 之间的边加入,而对于整体二分中同层的节点,\(mid\) 是单调的
所以维护一个单调指针对于每一层扫一遍即可,每当进入新的层之后我们就把指针变成 \(0\),并清空并查集
因为只有 \(log\) 层,所以只会清空 \(log\) 次,所以总复杂度就是 \(O(n*logn)\)

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,Q,fa[N],sz[N],ans[N];
struct node{int x,y,z,id;}e[N];
struct sub{int l,r;vector<node>S;};
queue<sub>q;
inline void Clear(){for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y){
    if(find(x)==find(y))return ;
    x=find(x);y=find(y);
    fa[y]=x;sz[x]+=sz[y];
}
inline int getval(int x,int y){
    x=find(x);y=find(y);
    int ret=sz[x]+sz[y];
    if(x==y)ret>>=1;
    return ret;
}
void solve(){
    int p=0;
    while(!q.empty()){
        sub s=q.front(),L,R;q.pop();
        if(s.l==s.r){
            for(int i=s.S.size()-1;i>=0;i--)ans[s.S[i].id]=s.l;
            continue;
        }
        int mid=(s.l+s.r)>>1;
        if(p>mid)p=0,Clear();
        while(p<mid)p++,merge(e[p].x,e[p].y);
        for(int i=s.S.size()-1;i>=0;i--){
            node t=s.S[i];
            if(getval(t.x,t.y)<t.z)R.S.push_back(t);
            else L.S.push_back(t);
        }
        L.l=s.l;L.r=mid;R.l=mid+1;R.r=s.r;
        q.push(L);q.push(R);
    }
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  scanf("%d%d",&n,&m);
  sub s;node t;
  for(int i=1;i<=m;i++)scanf("%d%d",&e[i].x,&e[i].y);
  scanf("%d",&Q);
  for(int i=1;i<=Q;i++){
      scanf("%d%d%d",&t.x,&t.y,&t.z);
      t.id=i;s.S.push_back(t);
  }
  s.l=1;s.r=m;q.push(s);Clear();
  solve();
  for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
  return 0;
}

转载于:https://www.cnblogs.com/Yuzao/p/8506386.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值