# [LOJ2865] P4899 [IOI2018] werewolf

P4899 [IOI2018] werewolf
LOJ Chen 2865. "IOI2018" werewolf , the first AC interactive question

kruskal reconstruction tree + chairman tree
In fact, if you know the algorithm of tree reconstruction, the difficulty lies in the chairman tree

It is customary to start labeling from \ (1 \), so the labeling in the following explanations starts from \ (1 \)
Start from \ (s \), only go to points \ (L, L + 1, cdots, n \), and the set of points you can go to is recorded as \ (V_1 \)
Starting from \ (e \), just walk \ (1,2,\cdots,R \), and the set of points you can walk to is recorded as \ (V_2 \)
Then, if \ (V_1\cap V_2 \neq \varnothing \), it means that there is a solution. We can change the form of human wolf at any point in the intersection

Step 1, find \ (V_1,V_2 \)
Consider kruskal to reconstruct the tree, go first Here I don't know if I read the more detailed explanation. I won't start with the content of refactoring tree here
Building two refactoring trees

• \(A \) is A reconstruction with \ (\ max(u,v) \) as the weight and the minimum spanning tree. It can be known that the minimum value of the maximum number of points in the path of \ (u,v \) is the point weight of \ (lca(u,v) \) in the reconstruction tree
• \(B \) is a reconstruction with \ (\ min(u,v) \) as the weight and the maximum spanning tree. It can be known that in \ (u,v \) two-point path, the maximum value of the minimum number of passing points is the point weight of \ (lca(u,v) \) in the reconstruction tree

Therefore, due to the general nature of kruskal's reconstruction tree, it can also be known that for the path between \ (A \) tree and A point \ (u \), the node whose minimum value of the maximum number of the passing points is less than or equal to \ (x \), that is, all leaf nodes in the subtree whose path from \ (u \) to the root has the lowest depth and whose weight is less than or equal to \ (x \) as the root
It can be used to practice the determination of sentence components
Then \ (x=R \), the point set thus obtained is \ (V_2 \)
Similarly, \ (B \) tree can be used to find \ (V_1 \) in a similar way

Step 2: find whether the intersection of \ (V_1,V_2 \) is not empty
Using the chairman tree, you can actually use the tree array offline, but you don't understand how to do it

In fact, the chairman tree can be understood as the prefix sum of the line tree. We rank these points (\ (2n-1 \) in the order of dfs in the \ (A \) tree, and build the chairman tree in the order of dfs in the \ (B \) tree
Then we set the two points (the root of the subtree) found by the reconstruction tree to be \ (a,b \), and since the dfs order is continuous in a subtree, whether there is a number in \ (dfn_b\cdots dfn_b+size_b-1 \) per query \ (dfn_a\cdots dfn_a+size_a-1 \)
It's not hard

``````#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define N 400006
#define M 400006
int n,m;
struct edge{
int u,v;
}e[M];
inline int get_max(int x,int y){return x>y?x:y;}
inline int get_min(int x,int y){return x<y?x:y;}
struct TREE{
int up[N*2],vertex;
int son[2][N];
int fa[19][N],size[N],dfn[N],dfscnt;
int val[N];
inline int find(int k){
return k==up[k]?k:up[k]=find(up[k]);
}
static inline int cmp_A(edge aa,edge aaa){return get_max(aa.u,aa.v)<get_max(aaa.u,aaa.v);}
static inline int cmp_B(edge aa,edge aaa){return get_min(aa.u,aa.v)>get_min(aaa.u,aaa.v);}
inline void build_A(){
std::sort(e+1,e+1+m,cmp_A);
vertex=n;
for(reg int i=1;i<=2*n;i++) up[i]=i;
for(reg int u,v,i=1,cnt=1;cnt<n;i++){
u=find(e[i].u);v=find(e[i].v);
if(u==v) continue;
val[++vertex]=get_max(e[i].u,e[i].v);
son[0][vertex]=u;son[1][vertex]=v;
cnt++;up[u]=up[v]=vertex;
}
}
inline void build_B(){
std::sort(e+1,e+1+m,cmp_B);
vertex=n;
for(reg int i=1;i<=2*n;i++) up[i]=i;
for(reg int u,v,i=1,cnt=1;cnt<n;i++){
u=find(e[i].u);v=find(e[i].v);
if(u==v) continue;
val[++vertex]=get_min(e[i].u,e[i].v);
son[0][vertex]=u;son[1][vertex]=v;
cnt++;up[u]=up[v]=vertex;
}
}
void dfs(int u,int father){
fa[0][u]=father;size[u]=1;dfn[u]=++dfscnt;
for(reg int i=1;i<19;i++) fa[i][u]=fa[i-1][fa[i-1][u]];
if(!son[0][u]) return;
dfs(son[0][u],u);dfs(son[1][u],u);
size[u]+=size[son[0][u]]+size[son[1][u]];
}
inline int get_A(int u,int x){
for(reg int i=18;~i;i--)if(val[fa[i][u]]<=x) u=fa[i][u];
return u;
}
inline int get_B(int u,int x){
for(reg int i=18;~i;i--)if(val[fa[i][u]]>=x) u=fa[i][u];
return u;
}
}A,B;
//Chairman tree part
struct tr{
tr *ls,*rs;
int x;
}dizhi[10000006],*root[N];
int tot;
inline int cmp(int x,int y){return A.dfn[x]<A.dfn[y];}
void build(tr *tree,int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
tree->ls=&dizhi[tot++];tree->rs=&dizhi[tot++];
build(tree->ls,l,mid);build(tree->rs,mid+1,r);
}
void insert(tr *last,tr *tree,int l,int r,int num,int k){
if(l==r) return tree->x=last->x+k,void();
int mid=(l+r)>>1;
*tree=*last;
if(num<=mid){
tree->ls=&dizhi[tot++];
insert(last->ls,tree->ls,l,mid,num,k);
}
else{
tree->rs=&dizhi[tot++];
insert(last->rs,tree->rs,mid+1,r,num,k);
}
tree->x=tree->ls->x+tree->rs->x;
}
int find(tr *left,tr *right,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return right->x-left->x;
int mid=(l+r)>>1;
if(ql<=mid){
if(find(left->ls,right->ls,l,mid,ql,qr)) return 1;
}
if(qr>mid){
if(find(left->rs,right->rs,mid+1,r,ql,qr)) return 1;
}
return 0;
}
int main(){
for(reg int i=1;i<=m;i++){
}
A.build_A();B.build_B();
A.dfs(2*n-1,2*n-1);B.dfs(2*n-1,2*n-1);
int tmp[n*2];
for(reg int i=1;i<n*2;i++) tmp[i]=i;
std::sort(tmp+1,tmp+n*2,cmp);
for(reg int i=0;i<2*n;i++) root[i]=&dizhi[tot++];
build(root[0],1,2*n-1);
for(reg int i=1;i<2*n;i++) insert(root[i-1],root[i],1,2*n-1,B.dfn[tmp[i]],tmp[i]<=n);
reg int s,t,L,R;
while(q--){