[hdu7171]Range Reachability Query
定义$f_{u,i}$表示点$i$能否通过$[l_{i},r_{i}]$中的边到达$v_{i}$,并用bitset维护
记$S_{k}=\{i\mid k\in [l_{i},r_{i}]\}$,则转移即$f_{u}|=f_{v}\& S_{k}$(其中$k$为$(u,v)$的编号)
关于$S_{k}$,即在$S_{k-1}$的基础上翻转$l_{i}=k$或$r_{i}=k-1$的位,可以预处理出
这样的内存为$\frac{(n+m)q}{8\cdot 1024}\ge 524288$,有以下两种优化方式:
1.将询问分为若干块,每块独立处理,这种做法常数过大,(可能)无法通过
2.将翻转的位分块,仅在块末尾存储$S_{k}$,查询时在上个块末尾的基础上调整
取块大小为$\sqrt{q}$,时间复杂度为$o(\frac{mq}{\omega}+m\sqrt{q})$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 50005 4 #define M 350 5 int t,n,m,q,k,x[N],y[N<<1],id[N<<1],pos[M],nex[N<<1]; 6 vector<int>e[N],v[N<<1];bitset<N>S0,S[M],f[N]; 7 void get_S(int k){ 8 S0=S[id[k]]; 9 for(int i=nex[pos[id[k]]];i<=k;i=nex[i]) 10 for(int j:v[i])S0.flip(j); 11 } 12 int main(){ 13 scanf("%d",&t); 14 while (t--){ 15 scanf("%d%d%d",&n,&m,&q); 16 for(int i=1;i<=n;i++)e[i].clear(); 17 for(int i=1;i<=m;i++){ 18 scanf("%d%d",&k,&y[i]); 19 e[k].push_back(i); 20 } 21 for(int i=1;i<=m;i++)v[i].clear(); 22 for(int i=1;i<=n;i++)f[i].reset(); 23 for(int i=1;i<=q;i++){ 24 scanf("%d%d",&x[i],&k),f[k].set(i); 25 scanf("%d",&k),v[k].push_back(i); 26 scanf("%d",&k),v[k+1].push_back(i); 27 } 28 k=id[0]=0,S0.reset(); 29 for(int i=1;i<=m;i++){ 30 k+=v[i].size(); 31 for(int j:v[i])S0.flip(j); 32 if (k>M)pos[++id[0]]=i,S[id[0]]=S0,k=0; 33 id[i]=id[0]; 34 } 35 k=m+1; 36 for(int i=m;i>=0;i--){ 37 nex[i]=k; 38 if (!v[i].empty())k=i; 39 } 40 for(int i=n;i;i--) 41 for(int j:e[i])get_S(j),f[i]|=(f[y[j]]&S0); 42 for(int i=1;i<=q;i++){ 43 if (f[x[i]][i])puts("YES"); 44 else puts("NO"); 45 } 46 } 47 return 0; 48 }