题解:
建两棵重构树,分别可以求出起点开始人形能去哪些点,那些点狼形可以到终点,那么只需要知道这两个集合是否有交集就行了,实际上是一个 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;
}