个点, 条有向边,每条有向边 满足 。 组询问,每次给定两个点 满足 ,判断是否能从 走到 ,强制在线。
,。
对于一个区间 ,设 ,则想要从 去 就一定要经过 中的至少一个点,所以可以分治预处理出每个区间中左半部分的点能到 中的哪些点,右半部分的点能由哪些点到达,用 bitset 维护一下。查询的时候直接找到对应的区间把 bitset 按位与一下即可。
代码如下:
#include <iostream>
#include <cstdio>
#include <bitset>
#include <vector>
using namespace std;
const int S=200005;
int n,m,k;
vector<int> g[S];
bitset<205> dp[25][S];
int q;
void init(int l,int r,int d)
{
if(l==r) return;
int mid=l+r>>1;
for(int i=mid;i<=min(mid+k,r);i++) dp[d][i][i-mid]=1;
for(int u=mid-1;u>=l;u--) for(int v:g[u]) if(v<=r) dp[d][u]|=dp[d][v];
for(int u=mid;u<=r;u++) for(int v:g[u]) if(v<=r) dp[d][v]|=dp[d][u];
init(l,mid,d+1),init(mid+1,r,d+1);
}
bool que(int l,int r,int d,int s,int t)
{
int mid=l+r>>1;
if(t<=mid) return que(l,mid,d+1,s,t);
else if(mid<s) return que(mid+1,r,d+1,s,t);
return (dp[d][s]&dp[d][t]).any();
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
}
init(1,n,0);
scanf("%d",&q);
int c=0;
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
x=((1ll*c*c)^x)%n+1,y=((1ll*c*c)^y)%n+1;
if(x>y) swap(x,y);
if(x==y||que(1,n,0,x,y)) c++,puts("Yes");
else puts("No");
}
return 0;
}