[LOJ]#2865. 「IOI2018」狼人 Kruskal重构树

题解:

建两棵重构树,分别可以求出起点开始人形能去哪些点,那些点狼形可以到终点,那么只需要知道这两个集合是否有交集就行了,实际上是一个 d f s dfs dfs序为坐标的二维数点,离线做就行了。

代码:

#include<bits/stdc++.h>
#include"werewolf.h"
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=200010;
const int Maxm=400010;
const int Maxq=200010;
const int inf=2147483647;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,m,Q,ans[Maxq];
struct Query
{
	int x,y,id,op;
	Query(int _x=0,int _y=0,int _id=0,int _op=0){x=_x,y=_y,id=_id,op=_op;}
}q[Maxq<<2];int lq=0;
bool cmpQ(Query a,Query b){return a.x<b.x;}
struct Edge{int x,y,d;};
bool cmp1(Edge a,Edge b){return a.d>b.d;}
bool cmp2(Edge a,Edge b){return a.d<b.d;}
struct Graph
{
	Edge e[Maxm];
	int tot;
	int dep[Maxn<<1],fa[Maxn<<1][19],val[Maxn<<1],rt[Maxn<<1],lc[Maxn<<1],rc[Maxn<<1];
	int in[Maxn<<1],out[Maxn<<1],dfn;
	int findrt(int x){return((rt[x]==x)?x:rt[x]=findrt(rt[x]));}
	void build()
	{
		for(int i=1;i<=n;i++)rt[i]=val[i]=i;
		for(int i=1;i<=m;i++)
		{
			int x=e[i].x,y=e[i].y;
			int fx=findrt(x),fy=findrt(y);
			if(fx==fy)continue;
			rt[fx]=rt[fy]=++tot;rt[tot]=tot;
			lc[tot]=fx,rc[tot]=fy;val[tot]=e[i].d;
		}
	}
	void dfs(int x,int ff)
	{
		dep[x]=dep[ff]+1,fa[x][0]=ff,in[x]=++dfn;
		for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
		if(x>n)dfs(lc[x],x),dfs(rc[x],x);
		out[x]=dfn;
	}
}G1,G2;
int P[Maxn];
bool cmpP(int a,int b){return G1.in[a]<G1.in[b];}
int get1(int x,int lim)
{
	for(int i=18;i>=0;i--)
	if((1<<i)<=G1.dep[x]&&G1.val[G1.fa[x][i]]>=lim)x=G1.fa[x][i];
	return x;
}
int get2(int x,int lim)
{
	for(int i=18;i>=0;i--)
	if((1<<i)<=G2.dep[x]&&G2.val[G2.fa[x][i]]<=lim)x=G2.fa[x][i];
	return x;
}
int s[Maxn<<1];
void add(int x){for(;x<=(n<<1)-1;x+=(x&-x))s[x]++;}
int query(int x){int re=0;for(;x;x-=(x&-x))re+=s[x];return re;}
vector<int>as;
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(),Q=_s.size();
	for(int i=1;i<=m;i++)
	{
		G1.e[i].x=G2.e[i].x=_x[i-1]+1;
		G1.e[i].y=G2.e[i].y=_y[i-1]+1;
		G1.e[i].d=min(G1.e[i].x,G1.e[i].y);
		G2.e[i].d=max(G2.e[i].x,G2.e[i].y);
	}
	sort(G1.e+1,G1.e+1+m,cmp1),sort(G2.e+1,G2.e+1+m,cmp2);
	G1.tot=G2.tot=n;
	G1.build(),G2.build();
	G1.dep[0]=G2.dep[0]=-1,G1.dfn=G2.dfn=0;
	G1.dfs(G1.tot,0),G2.dfs(G2.tot,0);
	for(int i=1;i<=Q;i++)
	{
		int S=_s[i-1]+1,E=_e[i-1]+1,L=_l[i-1]+1,R=_r[i-1]+1;
		if(S<L||E>R){ans[i]=0;continue;}
		int p1=get1(S,L),p2=get2(E,R);
		q[++lq]=Query(G1.out[p1],G2.out[p2],i,1);
		q[++lq]=Query(G1.in[p1]-1,G2.out[p2],i,-1);
		q[++lq]=Query(G1.out[p1],G2.in[p2]-1,i,-1);
		q[++lq]=Query(G1.in[p1]-1,G2.in[p2]-1,i,1);
	}
	sort(q+1,q+1+lq,cmpQ);
	for(int i=1;i<=n;i++)P[i]=i;sort(P+1,P+1+n,cmpP);
	int now=1;
	for(int i=1;i<=lq;i++)
	{
		while(now<=n&&G1.in[P[now]]<=q[i].x)add(G2.in[P[now]]),now++;
		ans[q[i].id]+=q[i].op*query(q[i].y);
	}
	for(int i=1;i<=Q;i++)as.push_back((ans[i]>0)?1:0);
	return as;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值