P6328 我是仙人掌 题解

P6328

一眼题。

首先处理出所有点之间的距离是简单的,可以用 BFS 在 $\mathcal{O}(n(n+m))$ 的时间内解决。

然后想一个相对暴力的做法,因为只要求至少一个二元组,那答案显然的等价于求出一个点集,使得每个点集中的点存在一个 $i$ 能够在 $y_i$ 步内到达 $x_i$。用一个类似染色的做法对所有 $x_i$ 做 $y_i$ 轮,显然就是被打了标记的点的数量。然后因为每个点至多只会被统计一次,每个 $x_i$ 互不干扰。容易想到使用 bitset 对每个 $x_i$ 能到达的点求交集。但是因为 $y_i$ 不一样,对每个点在预处理时用 $n$ 个 bitset 存储到它的距离 $\le i$ 的点集,这是 $\mathcal{O}(\frac{n^3}{w})$ 的。最后统计用一个 bitset 全局取并即可。

时间复杂度:$\mathcal{O}(\frac{n^3+n\sum a}{w})$。

空间复杂度:$\mathcal{O}(\frac{n^3}{w})$。

$20:43:00$ 我开始写。

$21:00:46$ 我写完了。配合光读喜提最优解。

Tips:接近完全图时 vector 明显快于链式前向星。

代码:

#define eb emplace_back
const int N=1e3+10;
int n,m,Q;
int dis[N];
bitset<N> b[N][N],vis,tmp;
vector<int> e[N];
int q[N],hd,tl,id[N];
void solve(int s){
    vis.reset();
    q[hd=tl=1]=s;dis[s]=0,vis[s]=1;b[s][0][s]=1;
    while(hd<=tl){
        int u=q[hd++];
        for(int v:e[u])if(!vis[v]){
            dis[v]=dis[u]+1;
            b[s][dis[v]][v]=1;
            vis[v]=1;
            q[++tl]=v;
        }
    }
    for(int i=1;i<=n;i++)b[s][i]|=b[s][i-1];
}
int main(){
    n=read(),m=read(),Q=read();
    for(int i=1,u,v;i<=m;i++)u=read(),v=read(),e[u].eb(v),e[v].eb(u);
    for(int i=1;i<=n;i++)solve(i);
    for(int qi=1;qi<=Q;qi++){
        int num=read();
        tmp.reset();
        for(int i=1,x,y;i<=num;i++)x=read(),y=read(),tmp|=b[x][y];
        we(tmp.count());
    }
    pcc();
    return 0;
}
posted @ 2023-10-13 20:43  Pengzt  阅读(6)  评论(0编辑  收藏  举报  来源