1. 程式人生 > >【題解】Luogu P5068 [Ynoi2015]我回來了

【題解】Luogu P5068 [Ynoi2015]我回來了

眾所周知lxl是個毒瘤,Ynoi道道都是神仙題,這道題極其良心,題面好評

原題傳送門

我們先珂以在\(O(n^2)\)的時間內bfs求出任意兩點距離

我們考慮如何計算從一個點到所有點的最短路長度小於等於k的點的數量

我們先求出來從一個點到所有點的最短路長度等於k的點的數量,這個珂以在bfs搜尋過程中完成

統計最短路長度小於等於k的點的數量珂以使用字首和

這裡明顯不好直接字首和,我們可以使用bitset來維護一個點到所有點的最短路長度小於等於k的點的數量,如果一位是1,就代表滿足條件,否則不滿足條件

做字首和時就直接用“|”就行了、

以上搜索和字首和的複雜度為\(O(\frac {n^3}{\omega})\)
\(\omega\)是一個常數,這裡珂以取32)

最後詢問時開一個bitset,把所有條件的答案“|”起來,就是求出滿足條件點的個數,最後輸出這個bitset的count(),也就是1(滿足)的個數

查詢的複雜度為\(O(\frac {n \sum_{i=1}^{q} a}{\omega})\)

這道題存邊不能用鏈式前向星,鏈式前向星會tle,因為地址不是連續的,所以用vector存邊就行了qaq

總複雜度為\(O(\frac {n^3+n \sum_{i=1}^{q} a}{\omega})\)

#include <bits/stdc++.h>
#define N 1010
#define M 100010
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf; 
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
vector <int> to[N];
int n,m,q;
int dis[N][N];
bitset <N> dissum[N][N];
inline void bfs(register int x,register int id)
{
    for(register int i=1;i<=n;++i)
        dis[id][i]=1005;
    queue <int> q;
    q.push(x);
    dis[id][x]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(register int i=0;i<to[u].size();++i)
            if(dis[id][to[u][i]]==1005)
            {
                dis[id][to[u][i]]=dis[id][u]+1;
                q.push(to[u][i]);
            }
    }
    for(register int i=1;i<=n;++i)
        dissum[id][dis[id][i]].set(i);
    for(register int i=1;i<=n;++i)
        dissum[id][i]|=dissum[id][i-1];
}
int main()
{
    n=read(),m=read(),q=read();
    while(m--)
    {
        int u=read(),v=read();
        to[u].push_back(v),to[v].push_back(u);
    }
    for(register int i=1;i<=n;++i)
        bfs(i,i);
    while(q--)
    {
        bitset <N> ans;
        int x=read();
        while(x--)
        {
            int u=read(),k=read();
            ans|=dissum[u][k];    
        }
        write(ans.count()),puts("");
    }
    return 0;
}