可以发现询问的即是“由起点开始‘只经过编号大于等于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 ;
}

Luogu4899 IOI2018狼人(kruskal重构树+主席树)的更多相关文章

  1. LOJ.2865.[IOI2018]狼人(Kruskal重构树 主席树)

    LOJ 洛谷 这题不就是Peaks(加强版)或者归程么..这算是\(IOI2018\)撞上\(NOI2018\)的题了? \(Kruskal\)重构树(具体是所有点按从小到大/从大到小的顺序,依次加入 ...

  2. [IOI2018] werewolf 狼人 [kruskal重构树+主席树]

    题意: 当你是人形的时候你只能走 \([L,N-1]\) 的编号的点(即大于等于L的点) 当你是狼形的时候你只能走 \([1,R]\) 的编号的点(即小于等于R的点) 然后问题转化成人形和狼形能到的点 ...

  3. luoguP4197:Peaks(Kruskal重构树+主席树)或者(点分树+离线)

    题意:有N座山,M条道路.山有山高,路有困难值(即点权和边权).现在Q次询问,每次给出(v,p),让求从v出发,只能结果边权<=p的边,问能够到达的山中,第K高的高度(从大到小排序). 思路:显 ...

  4. UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html 题解 套路啊. 先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵krus ...

  5. [IOI2018]狼人——kruskal重构树+可持久化线段树

    题目链接: IOI2018werewolf 题目大意:给出一张$n$个点$m$条边的无向图,点和边可重复经过,一个狼人初始为人形,有$q$次询问,每次询问要求人形态只能处于编号不小于$L$的点,狼形态 ...

  6. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  7. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  8. luogu4197 Peaks (kruskal重构树+主席树)

    按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...

  9. 洛谷P4197 Peaks(Kruskal重构树 主席树)

    题意 题目链接 往后中文题就不翻译了qwq Sol 又是码农题..出题人这是强行把Kruskal重构树和主席树拼一块了啊.. 首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的 ...

  10. [BZOJ3551][ONTAK2010]Peaks(加强版)(Kruskal重构树,主席树)

    3551: [ONTAK2010]Peaks加强版 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2438  Solved: 763[Submit][ ...

随机推荐

  1. day 3 创建窗口,移动-函数版

    1.创建窗口 #-*- coding:utf-8 -*- import pygame import time def main(): #1.创建窗口 screen = pygame.display.s ...

  2. React-精华版

    现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领 ...

  3. MySQL高级-MySQL安装

    1.mysql安装 检查系统是否安装过mysql 查询命令:rpm -qa|grep -i mysql 删除命令:rpm -e RPM软件包名(该名字是上一个命令查出来的名字) 安装命令:rpm -i ...

  4. PS 证件照换颜色

    1.打开要修改的图片,然后先Ctrl+J备份一份 2.点击魔法棒,点击要换颜色的地方,如衣服,之后会出现虚线,如果自动选择的不全,可以按住Shift键自行选择区域 3.然后Shift+Fn+F5(由于 ...

  5. 获取ip地址以及获取城市等信息

    class Program { static void Main(string[] args) { string ip = GetIP(); if (ip != null) { string city ...

  6. 【C++模版之旅】项目中一次活用C++模板(traits)的经历 -新注解

    问题与需求: 请读者先看这篇文章,[C++模版之旅]项目中一次活用C++模板(traits)的经历. 对于此篇文章提出的问题,我给出一个新的思路. talking is cheap,show me t ...

  7. (转)Shadow Mapping

    原文:丢失,十分抱歉,这篇是在笔记上发现的.SmaEngine 阴影和级联部分是模仿UE的结构设计   This tutorial will cover how to implement shadow ...

  8. vim常用命令—撤销与反撤销

    命令模式下(即按ESC后的模式) u 撤销 Ctrl r (组合键) 反撤销<后悔撤销>

  9. Python高级编程-多进程

    要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识. Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回 ...

  10. 求gcd(最大公因数),lcm(最小公倍数)模板

    gcd(最大公因数),lcm(最小公倍数) #include<iostream> using namespace std; int gcd(int a,int b)//辗转相除法(欧几里德 ...