可以发现询问的即是“由起点开始‘只经过编号大于等于l的点’所形成的连通块”与“由终点开始‘只经过编号小于等于r的点’所形成的连通块”是否有交集。于是建出重构树,就可以知道每个询问的连通情况了。现在要知道的是两个连通块的交集,考虑每个点是否有可能在里面。于是按照两棵重构树的dfs序给每个点一个二维坐标,问题就变为二维数点了,主席树即可。

  注意编号从0开始。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 200010
#define M 400010
int n,m,q,root[N<<],cnt;
struct data{int x,y;
}e[M];
struct data2{int l,r,x;
}tree[N<<];
bool cmp(const data&a,const data&b)
{
return a.y<b.y;
}
struct kruskal_tree
{
int t,p[N<<],cnt,tot,fa[N<<],value[N<<],dfn[N<<],size[N<<],f[N<<][];
struct data{int to,nxt;}edge[M<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int k)
{
dfn[k]=++tot;
size[k]=;
for (int i=p[k];i;i=edge[i].nxt)
{
f[edge[i].to][]=k;
dfs(edge[i].to);
size[k]+=size[edge[i].to];
}
}
int geta(int x,int k)
{
for (int j=;~j;j--) if (value[f[x][j]]>=k) x=f[x][j];
return x;
}
int getb(int x,int k)
{
for (int j=;~j;j--) if (value[f[x][j]]<=k) x=f[x][j];
return x;
}
void make()
{
for (int i=;i<=n;i++) fa[i]=i,value[i]=i;cnt=n;
for (int i=;i<=m;i++)
if (find(e[i].x)!=find(e[i].y))
{
int u=find(e[i].x),v=find(e[i].y);
cnt++;fa[u]=fa[v]=fa[cnt]=cnt;
addedge(cnt,u),addedge(cnt,v);
value[cnt]=e[i].y;
}
dfs(cnt);
f[cnt][]=cnt;
for (int j=;j<;j++)
for (int i=;i<=cnt;i++)
f[i][j]=f[f[i][j-]][j-];
}
}a,b;
void ins(int &k,int l,int r,int x)
{
tree[++cnt]=tree[k],k=cnt;tree[k].x++;
if (l==r) return;
int mid=l+r>>;
if (x<=mid) ins(tree[k].l,l,mid,x);
else ins(tree[k].r,mid+,r,x);
}
int query(int x,int y,int l,int r,int p,int q)
{
if (!x) return ;
if (l==p&&r==q) return tree[x].x>tree[y].x;
int mid=l+r>>;
if (q<=mid) return query(tree[x].l,tree[y].l,l,mid,p,q);
else if (p>mid) return query(tree[x].r,tree[y].r,mid+,r,p,q);
else return query(tree[x].l,tree[y].l,l,mid,p,mid)|query(tree[x].r,tree[y].r,mid+,r,mid+,q);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("wolf.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read(),q=read();
for (int i=;i<=m;i++)
{
e[i].x=read()+,e[i].y=read()+;
if (e[i].x>e[i].y) swap(e[i].x,e[i].y);
}
sort(e+,e+m+,cmp);
b.make();
for (int i=;i<=m;i++) swap(e[i].x,e[i].y);
sort(e+,e+m+,cmp);reverse(e+,e+m+);
a.make();
for (int i=;i<=n;i++) e[i].x=b.dfn[i],e[i].y=a.dfn[i];
sort(e+,e+n+,cmp);
for (int i=;i<=n;i++)
{
for (int j=e[i-].y+;j<=e[i].y;j++) root[j]=root[j-];
ins(root[e[i].y],,b.cnt,e[i].x);
}
for (int i=e[n].y+;i<=a.cnt;i++) root[i]=root[i-];
while (q--)
{
int x=read()+,y=read()+,l=read()+,r=read()+;
int u=a.geta(x,l),v=b.getb(y,r);
printf("%d\n",query(root[a.dfn[u]+a.size[u]-],root[a.dfn[u]-],,b.cnt,b.dfn[v],b.dfn[v]+b.size[v]-));
}
return ;
}

最新文章

  1. css-列表或标题的多级计数
  2. javascript 学习之自定义滚动条加滚轮事件
  3. 2016-12-14:通过static关键字,使用类成员函数作为回调函数
  4. 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)
  5. 在windows下配置Eclipse + go环境
  6. 修改Oracle权限的SQL及常见错误
  7. jdk
  8. 106. Construct Binary Tree from Inorder and Postorder Traversal
  9. git小操作之checkout、stash
  10. UITableView 表视图编辑
  11. WPF Button的背景图片设置
  12. JS简单仿QQ聊天工具的制作
  13. studio中集成.so文件的两种方式
  14. 顺序队列之C++实现
  15. 网际协议:无连接数据报交付(IPv4)
  16. Scrapy爬取豆瓣电影top250的电影数据、海报,MySQL存储
  17. 用webpack2.0构建vue2.0单文件组件超级详细精简实例
  18. .net异常机制
  19. 关于Java形参和实参的理解
  20. 转:jquery操作元素的css样式(获取、修改等等)

热门文章

  1. BZOJ1879_Bill的挑战_KEY
  2. day 11 绘制轮廓
  3. 创龙DSP6748学习之RS485收发
  4. c++ reference can not be reassigned
  5. Unity AssetBundle工作流
  6. Unity - Humanoid设置Bip骨骼导入报错
  7. javac 编译过程
  8. Spring Boot 示例项目
  9. zookeeper应用:屏障、队列、分布式锁
  10. spring java config 初探