【整体二分】AGC002D Stamp Rally

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82708608

题意:

给出一个无向图,Q次询问,每次询问给出两个点(x,y),求包含x,y的总大小不低于z的联通块(可能x,y不在一个联通块中),使得联通块中的边的序号最大值尽可能小。


分析:

好久没写整体二分了。。。

这里顺便复习一下:
对询问和答案同时二分,每次判断答案中间值后,把询问归为左右两类,使得每一层的时间复杂度均摊下来是O(n)级别的。

检查用并查集就行了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
struct Query{
    int id;
    int x,y,sz;
}que[MAXN],tmp[MAXN];
pair<int,int> link[MAXN];
int ans[MAXN];
int fa[22][MAXN],siz[22][MAXN];
int get_fa(int dep,int x){
    if(fa[dep][x]==0)
        return x;
    fa[dep][x]=get_fa(dep,fa[dep][x]);
    return fa[dep][x];
}
void add_edge(int l,int r,int dep){
    for(int i=l;i<=r;i++){
        int u=get_fa(dep,link[i].first);
        int v=get_fa(dep,link[i].second);
        if(u!=v){
            fa[dep][u]=v;
            siz[dep][v]+=siz[dep][u];   
        }
    }
}
int count(int dep,int x,int y,int sz){
    x=get_fa(dep,x);
    y=get_fa(dep,y);
    if(x==y)
        return siz[dep][x]>=sz;
    else
        return (siz[dep][x]+siz[dep][y])>=sz;
}
void Solve(int l,int r,int ql,int qr,int dep){
    if(l==r){
        for(int i=ql;i<=qr;i++)
            ans[que[i].id]=l;
        add_edge(l,r,dep);
        return ;    
    }
    int mid=(l+r)>>1;
    add_edge(l,mid,dep);
    int tl=ql,tr=qr;
    for(int i=ql;i<=qr;i++){
        if(count(dep,que[i].x,que[i].y,que[i].sz)==1)
            tmp[tl++]=que[i];
        else
            tmp[tr--]=que[i];
    }
    for(int i=ql;i<=qr;i++)
        que[i]=tmp[i];
    add_edge(mid+1,r,dep);
    Solve(l,mid,ql,tr,dep+1);
    Solve(mid+1,r,tl,qr,dep+1);
}
int main(){
    int n,m,q;
    SF("%d%d",&n,&m);
    for(int i=0;i<20;i++)
        for(int j=1;j<=n;j++)
            siz[i][j]=1;
    for(int i=1;i<=m;i++)
        SF("%d%d",&link[i].first,&link[i].second);
    SF("%d",&q);
    for(int i=1;i<=q;i++){
        SF("%d%d%d",&que[i].x,&que[i].y,&que[i].sz);
        que[i].id=i;
    }
    Solve(1,m,1,q,0);
    for(int i=1;i<=q;i++)
        PF("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/82708608