題意:個點條邊的無向圖,次詢問,每次給定,判斷是否存在一條到的路徑,使得路徑上可以找到一點,滿足此路徑的部分標號都且標號都(均包括端點)
顯然找到只走的點能到達的點集,只走能到達,判斷和是否有交即可
分別從大到小和從小到大建出Kruscal重構樹,發現和是樹上的一個子樹
什麼?只有點權怎麼建Kruscal重構樹?
因爲你走一條邊實際上受到了兩個端點的限制,所以直接取兩個點的當邊權就可以了
然後對和跑dfs序,設兩個dfs序數組分別爲
那麼對於點可以映射成平面上的
二維數點即可
因爲橫縱座標分別互不相同,所以寫主席樹會很清真
注意建Kruscal重構樹的虛點不要加到主席樹裏面,否則會出奇怪的問題
複雜度
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 600005
using namespace std;
inline int read()
{
int ans=0;
char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
struct edge{int u,v;}e[MAXN];
int n,m,q;
inline bool cmp1(const edge& a,const edge& b){return max(a.u,a.v)<max(b.u,b.v);}
inline bool cmp2(const edge& a,const edge& b){return min(a.u,a.v)>min(b.u,b.v);}
inline int Min(const int& x,const int& y){return x<y? x:y;}
inline int Max(const int& x,const int& y){return x>y? x:y;}
struct KruscalRestructTree
{
int f[MAXN],fa[MAXN][20],ch[MAXN][2],val[MAXN],cnt;
int dfn[MAXN],ed[MAXN],pos[MAXN],tim;
int find(int x){return f[x]==x? x:f[x]=find(f[x]);}
inline void init()
{
cnt=n;
for (int i=1;i<=n;i++) val[i]=i;
for (int i=1;i<=n+m;i++) f[i]=i;
}
inline void insert(int u,int v,int m(const int&,const int&))
{
u=find(u),v=find(v);
if (u==v) return;
f[u]=f[v]=fa[u][0]=fa[v][0]=++cnt;
ch[cnt][0]=u,ch[cnt][1]=v;
val[cnt]=m(val[u],val[v]);
}
void dfs(int u)
{
if (!u) return;
pos[dfn[u]=++tim]=u;
for (int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
dfs(ch[u][0]),dfs(ch[u][1]);
ed[u]=tim;
}
inline void query(int u,int& l,int& r,int ql,int qr)
{
if (val[u]<ql||qr<val[u]) return (void)(l=0);
for (int i=19;i>=0;i--)
if (fa[u][i]&&ql<=val[fa[u][i]]&&val[fa[u][i]]<=qr)
u=fa[u][i];
l=dfn[u],r=ed[u];
}
}S,T;
int ch[MAXN<<5][2],sum[MAXN<<5],cnt;
int rt[MAXN];
void insert(int& x,int y,int l,int r,int k)
{
x=++cnt;
ch[x][0]=ch[y][0],ch[x][1]=ch[y][1],sum[x]=sum[y]+1;
if (l==r) return;
int mid=(l+r)>>1;
if (k<=mid) insert(ch[x][0],ch[y][0],l,mid,k);
else insert(ch[x][1],ch[y][1],mid+1,r,k);
}
int query(int x,int l,int r,int ql,int qr)
{
if (ql<=l&&r<=qr) return sum[x];
if (qr<l||r<ql) return 0;
int mid=(l+r)>>1;
return query(ch[x][0],l,mid,ql,qr)+query(ch[x][1],mid+1,r,ql,qr);
}
int main()
{
n=read(),m=read(),q=read();
S.init(),T.init();
for (int i=1;i<=m;i++) e[i].u=read()+1,e[i].v=read()+1;
sort(e+1,e+m+1,cmp2);
for (int i=1;i<=m;i++) S.insert(e[i].u,e[i].v,Min);
sort(e+1,e+m+1,cmp1);
for (int i=1;i<=m;i++) T.insert(e[i].u,e[i].v,Max);
int tot=S.cnt;
S.dfs(tot),T.dfs(tot);
for (int i=1;i<=tot;i++)
if (S.pos[i]<=n) insert(rt[i],rt[i-1],1,tot,T.dfn[S.pos[i]]);
else rt[i]=rt[i-1];
while (q--)
{
int s,t,l,r;
s=read()+1,t=read()+1,l=read()+1,r=read()+1;
int lx,rx,ly,ry;
S.query(s,lx,rx,l,tot),T.query(t,ly,ry,1,r);
if (!lx||!ly){puts("0");continue;}
int ans=query(rt[rx],1,tot,ly,ry)-query(rt[lx-1],1,tot,ly,ry);
printf("%d\n",!!ans);
}
return 0;
}