P6592 [YsOI2020] 幼儿园
果然听课听一半是会出意外的……
题意简述
给定一个有 \(n\) 个点,\(m\) 条边的有向图。
按输入顺序排序,第 \(i\) 条边的边权为 \(i\)。
有 \(k\) 个询问,对于第 \(i\) 询问,会给出三个整数 \(x_i,l_i,r_i\)。需要你判断是否存在一条从点 \(x\) 到点 \(1\) 的路径,满足路径上的边的边权单调递减且取值范围为 \([l_i,r_i]\)。
数据范围与约定:\(1 \leq n \leq 10^5, 1 \leq m \leq 2 \times 10^5, 0 \leq k \leq 2 \times 10^5\)。
解题思路
首先我们可以注意到对于一条合法的从点 \(x\) 到点 \(1\)的路径,其边权最大的一条边一定是以点 \(x\) 为起点,边权最小的一条边一定是以点 \(1\) 为终点。且对于每个询问来说,终点 \(1\) 是不变的。所以我们可以考虑反向建边,并预处理出从点 \(1\) 出发的每条边,通过走边权单调递增的路径可以到达的其他边有哪些。在回答的时候,对于每一个点 \(x_i\),我们只需要从所有以它为终点的边中,找到一条边满足其边权不大于 \(r_i\) ,且在从点 \(1\) 出发的每条边中,有至少一条边的能到达它且其边权的在 \([l_i,r_i]\) 之中即可。
但是这样做的话显然会 MLE 和 TLE,我们先考虑如何优化空间。
对于某条边 \(e\),我们假设有 \(n\) 个从点 \(1\) 出发的边能够到达它,这些边按边权从小到大排序后分别为 \(e_1,e_2,...,e_n\)。不难发现,我们的路径上的边的最大值是确定的,也就是 \(e\) 的边权 \(val_e\)。而对于每一个与之相关的询问 \((x,l,r)\),在保证 \(val_e \in [l,r]\) 的前提下,我们只需要保证 \(e_n\) ,也就是从点 \(1\) 出发的能到达边 \(e\) 的权值最大的边,其边权 \(val_{e_n} \in [l,r]\) 即可,所以我们只需要预处理出每条边从点 \(1\) 出发的边中,能到达它的边的边权最大值就可以了,我们记第 \(i\) 条边的该值为 \(l_i\)。
于是问题就转化为了对于每一个询问 \((x,l,r)\),在所有能够到达点 \(x\) 的边中,找出一条边 \(i\)——假设它就是第 \(i\) 条边,满足 \(i \leq r\) 且 \(l_i \geq l\)。这里我用主席树会 MLE,所以我换了一种做法。
首先我们对每个点进行以下处理:对于点 \(x\),我们把所有以它为终点的边按其边权从小到大排序,记排完序后每条边的边权分别为\(e_1,e_2,...,e_n\),我们对每条边预处理出一个值 \(f_i\),\(f_i = \max \{l_{e_1},l_{e_2},...,l_{e_i}\}\)。由于 \(e_i \geq l_{e_i}\),所以对于每一个 \((f_i,e_i)\),肯定存在一个 \(e_j\),满足 \(e_j \in [f_i,e_i]\) 且 \(l_{e_j} = f_i\)。所以对于每一个询问 \((x,l,r)\),我们只需要二分出 \(r\) 在 \(e\) 中对应的位置后,判断对应位置的 \(f\) 值是否不小于 \(l\) 即可。
代码实现
变量名没有一一对应就是。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MN = 1e5,MM = 2e5;
int N,M,K,W;
int F[MN + 5];
vector<int> PM[MN + 5],R[MN + 5];
int main(){
scanf("%d%d%d%d",&N,&M,&K,&W);
for(int i = 1,u,v;i <= M;++i){
scanf("%d%d",&u,&v);
if(v == 1)
F[u] = i;
else
F[u] = max(F[u],F[v]);
PM[u].push_back(F[u]);
R[u].push_back(i);
}
for(int i = 1,sum = 0,x,l,r;i <= K;++i){
scanf("%d%d%d",&x,&l,&r);
x ^= sum * W,l ^= sum * W,r ^= sum * W;
if(x == 1){
putchar('1');
++sum;
putchar('\n');
continue;
}
int end = upper_bound(R[x].begin(),R[x].end(),r) - R[x].begin() - 1;
if(end >= 0 && end < PM[x].size() && PM[x][end] >= l){
putchar('1');
++sum;
}
else
putchar('0');
putchar('\n');
}
return 0;
}
浙公网安备 33010602011771号