题目链接:

IOI2018werewolf

题目大意:给出一张$n$个点$m$条边的无向图,点和边可重复经过,一个狼人初始为人形,有$q$次询问,每次询问要求人形态只能处于编号不小于$L$的点,狼形态只能处于编号不大于$R$的点,询问能否从$S$处于人形态然后在编号在$[L,R]$内的点变身一次成为狼人然后到达 $E$。

题目中编号都是从0开始,太不舒服了,我们按编号从1开始讲QAQ。

题目大意就是询问每次从一个点开始走只能走编号在[l,n]中的点,在任意点变成狼,之后只能走[0,r]中的点,是否能到达另一个点。

后一部分其实就是找有哪些点只走[0,r]中的点能到达终点,那么反过来看,就是终点只走[0,r]中的点能到达哪些点。

那么只要起点能到达的点和终点能到达的点中有交集就有解。

因为起点只能走一些编号较大的点,那么我们求出原图的最大生成树,建出kruskal重构树,求出重构树的dfs序,每次询问在重构树上倍增找能到达的联通块在dfs序上的区间就好了。

相反,从终点走就求出原图的最小生成树,然后也按上述方法找。

找到两段dfs序区间后只要这两段区间中有相同点就能判有解。

我们将每个点在第一个dfs序中的位置作为横坐标,在第二个dfs序中的位置作为纵坐标,剩下的就是一个简单的二维数点问题了。

等会,上面是不是差点什么?原图没有边权啊?

我们以最大生成树为例,对于一条边(x,y),两个点能否通过这条边互相到达,由这两个点中较小的点决定,因此求最大生成树时每条边边权就是边两端点中较小的那个。最小生成树边权就是两端点中较大的那个。

整体思路就是分别建出原图最小生成树和最大生成树的重构树,分别求出每个点在两个重构树中的dfs序位置,然后可持久化线段树二维数点。

kruskal重构树在这里就不赘述了,如果不是太了解可以参考我的另一篇博客NOI2018归程,那道题和这道题思想很像。

题面似乎没说保证整张图联通,因此可能是kruskal重构森林。

#include"werewolf.h"
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct miku
{
int u,v,x,y;
}a[400010];
int cnt;
int n,m,k;
int s,t,l,r;
int num1,num2;
int sum1,sum2;
int s1[400010];
int s2[400010];
int t1[400010];
int t2[400010];
int q1[400010];
int q2[400010];
int v1[400010];
int v2[400010];
int fa1[400010];
int fa2[400010];
int ls1[400010];
int rs1[400010];
int ls2[400010];
int rs2[400010];
int ls[5000010];
int rs[5000010];
int vis1[400010];
int vis2[400010];
int sum[5000010];
int root[200010];
int f1[400010][18];
int f2[400010][18];
vector<int>res;
int find1(int x)
{
if(fa1[x]==x)
{
return x;
}
return fa1[x]=find1(fa1[x]);
}
int find2(int x)
{
if(fa2[x]==x)
{
return x;
}
return fa2[x]=find2(fa2[x]);
}
bool cmp1(miku a,miku b)
{
return a.x>b.x;
}
bool cmp2(miku a,miku b)
{
return a.y<b.y;
}
void build(int &rt,int l,int r)
{
rt=++cnt;
if(l==r)
{
return ;
}
int mid=(l+r)>>1;
build(ls[rt],l,mid);
build(rs[rt],mid+1,r);
}
void updata(int &rt,int pre,int l,int r,int k)
{
rt=++cnt;
sum[rt]=sum[pre]+1;
if(l==r)
{
return;
}
ls[rt]=ls[pre];
rs[rt]=rs[pre];
int mid=(l+r)>>1;
if(k<=mid)
{
updata(ls[rt],ls[pre],l,mid,k);
}
else
{
updata(rs[rt],rs[pre],mid+1,r,k);
}
}
int query(int x,int y,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return sum[y]-sum[x];
}
int mid=(l+r)>>1;
int res=0;
if(L<=mid)
{
res+=query(ls[x],ls[y],l,mid,L,R);
}
if(R>mid)
{
res+=query(rs[x],rs[y],mid+1,r,L,R);
}
return res;
}
void dfs1(int x)
{
vis1[x]=1;
s1[x]=sum1;
if(x<=n)
{
q1[++sum1]=x;
}
for(int i=1;i<=17;i++)
{
f1[x][i]=f1[f1[x][i-1]][i-1];
}
if(ls1[x])
{
dfs1(ls1[x]);
}
if(rs1[x])
{
dfs1(rs1[x]);
}
t1[x]=sum1;
}
void dfs2(int x)
{
vis2[x]=1;
s2[x]=sum2;
if(x<=n)
{
q2[++sum2]=x;
}
for(int i=1;i<=17;i++)
{
f2[x][i]=f2[f2[x][i-1]][i-1];
}
if(ls2[x])
{
dfs2(ls2[x]);
}
if(rs2[x])
{
dfs2(rs2[x]);
}
t2[x]=sum2;
}
int ST1(int x,int val)
{
for(int i=17;i>=0;i--)
{
if(v1[f1[x][i]]>=val&&f1[x][i]!=0)
{
x=f1[x][i];
}
}
return x;
}
int ST2(int x,int val)
{
for(int i=17;i>=0;i--)
{
if(v2[f2[x][i]]<=val&&f2[x][i]!=0)
{
x=f2[x][i];
}
}
return x;
}
vector<int> check_validity(int N,vector<int> X,vector<int> Y,vector<int> S,vector<int> E,vector<int> L,vector<int> R)
{
n=N;
m=X.size();
k=S.size();
for(int i=1;i<=m;i++)
{
a[i].u=X[i-1];
a[i].v=Y[i-1];
a[i].u++;
a[i].v++;
a[i].x=min(a[i].u,a[i].v);
a[i].y=max(a[i].u,a[i].v);
}
for(int i=1;i<2*n;i++)
{
fa1[i]=i;
fa2[i]=i;
}
num1=num2=n;
sort(a+1,a+1+m,cmp1);
for(int i=1;i<=m;i++)
{
int fx=find1(a[i].u);
int fy=find1(a[i].v);
if(fx!=fy)
{
num1++;
v1[num1]=a[i].x;
ls1[num1]=fx;
rs1[num1]=fy;
f1[fx][0]=num1;
f1[fy][0]=num1;
fa1[fx]=num1;
fa1[fy]=num1;
if(num1==2*n-1)
{
break;
}
}
}
for(int i=1;i<=n;i++)
{
if(!vis1[i])
{
dfs1(find1(i));
}
}
sort(a+1,a+1+m,cmp2);
for(int i=1;i<=m;i++)
{
int fx=find2(a[i].u);
int fy=find2(a[i].v);
if(fx!=fy)
{
num2++;
v2[num2]=a[i].y;
ls2[num2]=fx;
rs2[num2]=fy;
f2[fx][0]=num2;
f2[fy][0]=num2;
fa2[fx]=num2;
fa2[fy]=num2;
if(num2==2*n-1)
{
break;
}
}
}
for(int i=1;i<=n;i++)
{
if(!vis2[i])
{
dfs2(find2(i));
}
}
build(root[0],1,n);
for(int i=1;i<=n;i++)
{
updata(root[i],root[i-1],1,n,s2[q1[i]]+1);
}
for(int i=0;i<k;i++)
{
s=S[i],t=E[i],l=L[i],r=R[i];
s++,t++,l++,r++;
s=ST1(s,l);
t=ST2(t,r);
int ans=query(root[s1[s]],root[t1[s]],1,n,s2[t]+1,t2[t]);
ans==0?res.push_back(0):res.push_back(1);
}
return res;
}

[IOI2018]狼人——kruskal重构树+可持久化线段树的更多相关文章

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

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

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

    [IOI2018] werewolf 狼人 LG传送门 kruskal重构树好题. 日常安利博客文章 这题需要搞两棵重构树出来,这两棵重构树和我们平时见过的重构树有点不同(据说叫做点权重构树?),根据 ...

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

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

  4. BZOJ3551: [ONTAK2010]Peaks加强版【Kruskal重构树】【主席树】

    重要的事情说三遍 不保证图联通 不保证图联通 不保证图联通 那些和我一样认为重构树是点数的童鞋是要GG Description [题目描述]同3545 Input 第一行三个数N,M,Q. 第二行N个 ...

  5. BZOJ3551 ONTAK2010Peaks加强版(kruskal重构树+dfs序+主席树)

    kruskal重构树本质就是给并查集显式建树来替代可持久化并查集.将边按困难度从小到大排序后建出该树,按dfs序建主席树即可.查询时跳到深度最浅的满足在该重要度下已被合并的点,在子树内查询第k大. # ...

  6. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  7. 【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

    这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,L ...

  8. BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增

    建出来 $Kruskal$ 重构树. 将询问点向上跳到深度最小,且合法的节点上. 那么,得益于重构树优美的性质,这个最终跳到的点为根的所有子节点都可以与询问点互达. 对于子树中求点权第 $k$ 大的问 ...

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

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

随机推荐

  1. 5-(基础入门篇)学会刷Wi-Fi模块固件(刷LUA版本固件)

    http://www.cnblogs.com/yangfengwu/p/9065559.html 基础教程源码链接请在淘宝介绍中下载,由于链接很容易失效,如果失效请联系卖家,谢谢 https://it ...

  2. http一次请求过程

    物理层:支持底层网络协议: 其中网络层支持IP协议: 传输层支持TCP协议,它是面向连接的: 应用层支持 http,ftp  tftp,SMTP,DHCP协议 一个完整的http请求过程: 1.浏览器 ...

  3. How to Enable TLS 1.2 on Windows Server 2008 R2 and IIS 7.5

    Nowadays there is an SSL vulnerability called POODLE discovered by Google team in SSLv3 protocol. So ...

  4. odoo 11 实现多个字段对应一个查询参数的查询

    在整理英语单词开发模块的过程中,有这样一个需求,就是我在查询界面里输入一个查询的值A,这个A可能是下面的任何一个值 1.一个英语单词  2.汉语文字  3.一个英语单词的部分 这里有两张表:engli ...

  5. JDK1.7 HashMap 导致循环链表

    转载自:疫苗:JAVA HASHMAP的死循环 在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race C ...

  6. 微信小程序 canvas 绘图问题总结

    业务中碰到微信小程序需要生成海报进行朋友圈分享,这个是非常常见的功能,没想到实际操作的时候花了整整一天一夜才搞好,微信的 canvas 绘图实在是太难用了,官方快点优化一下吧. 业务非常简单,只需要将 ...

  7. go陷阱

    必看的题目:https://blog.csdn.net/weiyuefei/article/details/77963810 1.关于值传递.引用传递与指针传递 当一个变量或者新值被创建时, 如果没有 ...

  8. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [五] 如何做全站采集?

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 如何做全站采集? 很多同学加群都在问, 如何使用Dotne ...

  9. Oracle数据库冷备份与热备份操作梳理

    Oracle数据库的备份方式有冷备份和热备份两种,针对这两种备份的实施过程记录如下: 一.Oracle冷备份 概念数据库在关闭状态下完成所有物理系统文件拷贝的过程,也称脱机备份.适合于非归档模式(即n ...

  10. 【MOOC EXP】Linux内核分析实验八报告

    程涵  原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 进程的切换和系统的一般执行过程 知识点 ...