题解 洛谷 P4899 【[IOI2018] werewolf 狼人】
先考虑狼形,其只能走编号小于\(R\)的点。若将每条边赋边权为其两端点编号的较大值,然后按最小生成树的顺序构建\(Kruskal\)重构树。
那么从原图的一个点\(x\)在树上倍增,到达满足要求且深度最浅的节点,该节点子树内所有原图中的点,狼形从\(x\)都能到达。
同样的,人形构建重构树就是边权为两端点编号的较小值,按最大生成树的顺序。
先构建这两棵\(Kruskal\)重构树,对于每次询问,只需查询起点和终点分别树上倍增后子树内的节点是否有交即可。
判断有交可以通过\(dfs\)序。设两棵重构树分别为\(A\)和\(B\),对于一个点在两棵树上的\(dfs\)序看作点对的形式\((dfn_A,dfn_B)\)。因为子树中的\(dfs\)序都是连续的,所以就把问题转化为二维数点。可以对\(dfn_A\)这一维构建主席树,\(dfn_B\)作为权值插入,判断有交只需看矩形中是否存在点即可。
具体实现看代码吧。
\(code:\)
#include<bits/stdc++.h>
#define maxn 1200010
#define maxm 10000010
#define inf 1000000000
#define mid ((l+r)>>1)
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,q,tree_cnt;
int p[maxn],rt[maxn],cnt[maxm],ls[maxm],rs[maxm];
struct Edge
{
int x,y;
}ed[maxn];
bool cmp1(const Edge &a,const Edge &b)
{
return max(a.x,a.y)<max(b.x,b.y);
}
bool cmp2(const Edge &a,const Edge &b)
{
return min(a.x,a.y)>min(b.x,b.y);
}
struct node
{
int tot,dfn_cnt;
int val[maxn],fa[maxn],f[maxn][25],in[maxn],out[maxn];
struct edge
{
int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
e[++edge_cnt]=(edge){to,head[from]};
head[from]=edge_cnt;
}
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void dfs(int x)
{
for(int i=1;i<=20;++i) f[x][i]=f[f[x][i-1]][i-1];
in[x]=++dfn_cnt;
for(int i=head[x];i;i=e[i].nxt) dfs(e[i].to);
out[x]=dfn_cnt;
}
void build(int type)
{
tot=n;
if(!type) sort(ed+1,ed+m+1,cmp1);
else sort(ed+1,ed+m+1,cmp2);
for(int i=1;i<=2*n-1;++i) fa[i]=i;
for(int i=1;i<=m;++i)
{
int x=find(ed[i].x),y=find(ed[i].y);
if(x==y) continue;
if(!type) val[++tot]=max(ed[i].x,ed[i].y);
else val[++tot]=min(ed[i].x,ed[i].y);
add(tot,y),add(tot,x),fa[x]=fa[y]=f[x][0]=f[y][0]=tot;
if(tot==2*n-1) break;
}
dfs(tot);
}
int get(int x,int v,int type)
{
for(int i=20;i>=0;--i)
{
if(!type&&f[x][i]&&val[f[x][i]]<=v) x=f[x][i];
if(type&&f[x][i]&&val[f[x][i]]>=v) x=f[x][i];
}
return x;
}
}A,B;
bool cmp3(const int &a,const int &b)
{
return A.in[a]<A.in[b];
}
void modify(int l,int r,int pos,int v,int &cur)
{
int x=++tree_cnt;
ls[x]=ls[cur],rs[x]=rs[cur],cnt[x]=cnt[cur]+v,cur=x;
if(l==r) return;
if(pos<=mid) modify(l,mid,pos,v,ls[cur]);
else modify(mid+1,r,pos,v,rs[cur]);
}
int query(int L,int R,int l,int r,int x,int y)
{
if(L<=l&&R>=r) return cnt[y]-cnt[x];
int v=0;
if(L<=mid) v+=query(L,R,l,mid,ls[x],ls[y]);
if(R>mid) v+=query(L,R,mid+1,r,rs[x],rs[y]);
return v;
}
int main()
{
read(n),read(m),read(q);
for(int i=1;i<=m;++i)
{
read(ed[i].x),read(ed[i].y);
ed[i].x++,ed[i].y++;
}
A.build(0),B.build(1);
for(int i=1;i<=2*n-1;++i) p[i]=i;
sort(p+1,p+2*n,cmp3);
for(int i=1;i<=2*n-1;++i)
rt[i]=rt[i-1],modify(1,2*n-1,B.in[p[i]],p[i]<=n,rt[i]);
while(q--)
{
int x,y,l,r;
read(x),read(y),read(l),read(r);
x++,y++,l++,r++,x=B.get(x,l,1),y=A.get(y,r,0);
if(query(B.in[x],B.out[x],1,2*n-1,rt[A.in[y]-1],rt[A.out[y]])) puts("1");
else puts("0");
}
return 0;
}
题解 洛谷 P4899 【[IOI2018] werewolf 狼人】的更多相关文章
- [LOJ2865] P4899 [IOI2018] werewolf 狼人
P4899 [IOI2018] werewolf 狼人 LOJ#2865.「IOI2018」狼人,第一次AC交互题 kruskal 重构树+主席树 其实知道重构树的算法的话,难度就主要在主席树上 习惯 ...
- p4899 [IOI2018] werewolf 狼人
分析 我用的主席树维护qwq 代码 #include<iostream> #include<cstdio> #include<cstring> #include&l ...
- [IOI2018] werewolf 狼人
[IOI2018] werewolf 狼人 IOI2018题解 (其实原题强制在线,要用主席树) 代码: 注意: 1.下标从0~n-1 2.kruskal重构树开始有n个节点,tot从n开始,++to ...
- [IOI2018] werewolf 狼人 kruskal重构树,主席树
[IOI2018] werewolf 狼人 LG传送门 kruskal重构树好题. 日常安利博客文章 这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据 ...
- 题解 洛谷P5018【对称二叉树】(noip2018T4)
\(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...
- 题解 洛谷 P3396 【哈希冲突】(根号分治)
根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...
- 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)
题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...
- 题解-洛谷P4229 某位歌姬的故事
题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...
- 题解-洛谷P4724 【模板】三维凸包
洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...
随机推荐
- 二叉查找树、平衡二叉树(AVLTree)、平衡多路查找树(B-Tree),B+树
B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引. B+树中的B代表平衡(balance),而不是二叉(binary),因为B+树是从最早的平衡二叉树演化而来的. 在 ...
- 新老单点的改造——-理解Cookie、Session、Token
近期参与了新老单点的改造,一直想总结一下,发现这篇文章比较贴切. 整理了如下: 随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录 ...
- elasticserach数据库深度分页查询的原理
深度分页存在的问题 https://segmentfault.com/a/1190000019004316?utm_source=tag-newest 在实际应用中,分页是必不可少的,例如,前端页面展 ...
- vue多个项目公共化组件方案
前言 最近项目需求,需要把两个vue项目多个一样的模块抽成公共化.考虑采用的方案 1.把公共部分独立出来一个项目,npm发布私有包,使用的项目npm install下载(目前下载使用出现配置错误) 存 ...
- HTML5实现DTMF(电话拨号按键信号)解码、编码,代码简单易于移植
目录 一.前言 1.1 HTML5实现DTMF的一些动机 1.2 一些有效场景 (1) 10086 (2) 软电话 (3) 小玩具 二.DTMF频率按键对照表 三.DTMF信号解码 得到按键值 3.1 ...
- P1131 [ZJOI2007]时态同步【树形dp】
时态同步 从叶子到根节点统计修改次数.树形\(dp\)思想. 题目描述 小\(Q\)在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字\(1,2,3-\). ...
- 【树形dp】 bzoj1131 Sta
题目 给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 Input 给出一个数字N,代表有N个点.N<=1000000 下面N-1条边. Output 输出你所找到的点 ...
- python unittest自动测试框架
编写函数或者类时进行测试,确保代码正常工作 python unittest 模块提供了代码测试工具.按照定义测试包括两部分:管理测试依赖库的代码(称为‘固件’)和测试本身. 单元测试用于核实函数的某 ...
- lodash - slice
稀疏数组和密集数组 稀疏数组 Sparse arrays 一般来说,JavaScript 中的数组都是稀疏数组-它们可以拥有空槽,所谓空槽,指的就是数组的某个位置没有任何值,既不是 undefined ...
- call,apply,bind的内部原理实现
call call 方法使用一个函数执行的时候更改本身 this 指向,并传入一个或者多个参数. var obj = { name: '$call' } function _fun() { conso ...