可以发现询问的即是“由起点开始‘只经过编号大于等于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. UItraIso 制作ubentu 系统失败

    设备忙,请退出所有正在运行的应用程序,按确定按钮重试. 解决方法: 不要使用UItraIso,不知道为什么一直不行.重启了电脑几次都不行.用Rufus吧 https://rufus.ie/ 注意: r ...

  2. 一个例子说明substr(), mb_substr() 和 mb_strcut()之间的区别

    例子来自PHP官方文档,我只是翻译下. http://www.php.net/manual/zh/function.mb-strcut.php header( 'Content-Type:text/h ...

  3. MyBatis-SELECT基本查询

    1.返回一个LIST <!-- public List<Employee> getEmpsByLastNameLike(String lastName); --> <!- ...

  4. 「日常训练」Maximum Multiple(HDU-6298)

    题意与分析 一开始以为是一条高深的数学题,跳过去了,后来查其他题目的代码的时候无意看到,一看emmmmmm 稍微思考一下就有了.\(1=\frac{1}{3}+\frac{1}{3}+\frac{1} ...

  5. hdu2094产生冠军(思维题)

    产生冠军 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  6. hdu1171Big Event in HDU(01背包)

    Big Event in HDU Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  7. jmeter属性设置

    使用${__setProperty(newuserid,1,)}函数对属性进行设置 2.使用${__P(userid)}函数在其他线程组中引用该属性 备注: 1.JMeter属性在测试脚本的任何地方都 ...

  8. django 与 flask里面从已有数据库表中反向生成models

    django: 配置好数据库连接 python manage.py  inspectdb  > models.py 即可反向生成orm使用的models, 注意: > 后面可以定义为指定路 ...

  9. lintcode735. Replace With Greatest From Right

    Given an array of integers, replace every element with the next greatest element (greatest element o ...

  10. Idea Live Templates

    常用live templates 模板 注释 : * * @param $params$ * @return $return$ * $date$ $time$ chiyuanzhen743 */ lo ...