描述
小A和一些朋友来到了一个热带花园游玩。花园中有 n 个喷泉(标号 0 ~ n−1 ),以及 m条双向道路。
每条道路有个互不相同的美丽程度,当一个人在节点 x 时,他会选择一条与 x 相连的最美丽的道路走过去,如果他在前一时刻是从那条道路走过来的,则他会选择美丽程度次大的道路走(如果不存在次大的,则还是走最大的那条)。保证每个点都至少有一条边与它相连。
一开始每个点上都有一个人,他们将按照上述规则行走,每单位时间所有人都走过一条道路。
在 P 号点上有一个豪华餐厅,你需要计算在 Ki 时间后恰好在 P 号点上的人数。
有 q 组 Ki 需要你计算,每组的 P 都相同,询问互相独立。
输入格式
第一行三个数 n, m, P。
接下来M行,每行两个数 x , y 表示一条道路。道路按照美丽程度从大到小给出。
接下来一行一个数 q 。
接下来一行,q 个正整数 Ki。
输出格式
一行Q个数,表示每次询问的答案。
样例1
样例输入1
5 5 2
1 0
1 2
3 2
1 3
4 2
2
3 1
样例输出1
1 2
样例2
样例输入2
6 6 0
1 2
0 1
0 3
3 4
4 5
1 5
1
3
样例输出2
2
限制与约定
对于 30% 的数据,n≤1000n≤1000, m≤10000m≤10000, Ki≤100Ki≤100。
对于 60% 的数据,q=1q=1。
对于 100% 的数据,2≤n≤150000, 1≤m≤150000 1≤q≤2000, 1≤Ki≤ 109 10 9 。
时间限制:1s
空间限制:512MB
可以发现每个点最大和次大会走的点是可以
O(n)
O
(
n
)
预处理出来的
直接做会比较麻烦 我们把点拆开做
有个很显然的性质就是一个联通块肯定是个基环内向树
那么很显然,每个点分为三种情况:
①到不了p
②仅到一次p
③到p之后沿着环走多次经过p
那我们把p分为在环上,不在环上考虑
预处理出每个点到p的距离统计答案即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(register int i = j;i <= k;++i)
#define repp(i,j,k) for(register int i = j;i >= k;--i)
#define ll long long
#define P pair<int,int>
const int INF = 0x7fffffff;
int n , m , p , Q;
int linkk[151000] , t;
int to1[151000] , to2[151000] , to[301000];
int dis[301000][3];
int ans[3][301000];
bool flag[301000][3];
int len_A , len_B , tmp;
int K;
bool vis[301000];
P q[2010];
struct node{
int n , y , v;
}e[601000];
namespace fastIO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if (p1==pend){
p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
if (pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline void read(int &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
inline void read(ll &x){
bool sign=0; char ch=nc(); x=0;
for (;blank(ch);ch=nc());
if (IOerror)return;
if (ch=='-')sign=1,ch=nc();
for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if (sign)x=-x;
}
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
void insert(int x,int y,int z)
{
e[++t].y = y;e[t].n = linkk[x];e[t].v = z;linkk[x] = t;
return;
}
void pre()
{
rep(x,0,n-1)
{
int Max = 0 , Max_ = 0 , k1 = -1,k2 = -1;
for(int j = linkk[x];j;j = e[j].n)
if(e[j].v > Max)
{
Max_ = Max;k2 = k1;
Max = e[j].v;k1 = e[j].y;
}
else
if(e[j].v > Max_)
Max_ = e[j].v,k2 = e[j].y;
to1[x] = k1;to2[x] = k2;
if(k2 == -1) to2[x] = to1[x];
}
return;
}
void make_node()
{
memset(linkk,0,sizeof(linkk));t = 0;
rep(i,0,n-1)
{
int t = to1[i];
if(to1[t] != i) to[i] = t;
else to[i] = t+n;
t = to2[i];
if(to1[t] != i) to[i+n] = t;
else to[i+n] = t + n;
}
return;
}
void dfs_pre(int x,int T)
{
if(vis[x]){
if(x != T) tmp = -1;
return;
}
vis[x] = true;
dfs_pre(to[x],T);
if(tmp >= 0)tmp++;
vis[x] = false;
return;
}
void dfs(int x,int T,int num)
{
if(flag[x][num]) return;
if(vis[x])
{
dis[x][num] = -1;
flag[x][num] = true;
return;
}
if(x == T) return;
vis[x] = true;
dfs(to[x],T,num);
vis[x] = false;
dis[x][num] = dis[to[x]][num] == -1?-1:dis[to[x]][num] + 1;
flag[x][num] = true;
return;
}
void get()
{
rep(i,0,2*n-1)
if(!flag[i][1])
dfs(i,p,1);
rep(i,0,2*n-1)
if(!flag[i][2])
dfs(i,p+n,2);
return;
}
void init()
{
read(n);read(m);read(p);
rep(i,1,m)
{
int x,y;
read(x);read(y);
insert(x,y,m-i+1);
insert(y,x,m-i+1);
}
pre();
dis[p][1] = dis[p+n][2] = 0;
make_node();
dfs_pre(p,p);len_A = tmp;tmp = 0;
dfs_pre(p+n,p+n);len_B = tmp;
get();
}
void work(int p,int f)
{
int lazy = dis[to[p]][f] == -1 ? -1 : dis[to[p]][f] + 1;
rep(i,0,n-1)
if(dis[i][f] >= 0)
{
ans[0][dis[i][f]]++;
ans[1][dis[i][f] % lazy]++;
}
if(lazy == -1)
rep(i,1,Q) q[i].second += q[i].first <= 150000 ? ans[0][q[i].first] : 0;
else
{
rep(i,lazy,150000) ans[0][i] += ans[0][i - lazy];
rep(i,1,Q) q[i].second += q[i].first <= 150000 ? ans[0][q[i].first] : ans[1][q[i].first % lazy];
}
return;
}
int main()
{
init();
read(Q);
rep(i,1,Q) read(q[i].first);
work(p,1);
memset(ans,0,sizeof(ans));
work(p+n,2);
rep(i,1,Q) printf("%d ",q[i].second);
return 0;
}