[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})$,可以通过

 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 }
View Code

 

posted @ 2022-07-26 22:29  PYWBKTDA  阅读(140)  评论(0编辑  收藏  举报