uoj407 【IOI2018】狼人

link

 

题意:

给一张n个点m条边的无向图,有q个询问,每次询问给出s,t,l,r,问你能否从s走到t,并且初始为人形,结束时必须为狼形,你是人形的时候必须避开$[1,l)$的节点,狼形的时候必须避开$(r,n]$的节点,你只能在$[L,R]$的节点处变身?

$n,q\leq  2\times 10^5,m\leq 4\times 10^5.$

 

题解:

get技能——Kruskal重构树

重构树是一个类似堆的结构,节点u比它的所有儿子v的权都要来的小/大(在这题中都有用到),可以用并查集建树。

考虑题中s~t有合法路径相当于,s只经过L~N的点能到达的点集和t只经过1~R的点能到达的点集有交。

那么考虑建出Kruskal最大/小重构树,那么两个点集分别对应到两棵树上的一个子树,求出dfs序转化成两个区间。

把每个点对应到一个坐标$[dfn1,dfn2]$(在两棵树中dfs序上的位置),原问题等价于询问一个矩形$x∈[l1,r1],y∈[l2,r2]$中是否有点,离线树状数组即可。

复杂度$\mathcal{O}(n\log n)$。

 

code:

 1 #include<bits/stdc++.h>
 2 #include "werewolf.h"
 3 #define rep(i,x,y) for (int i=(x);i<=(y);i++)
 4 #define per(i,x,y) for (int i=(x);i>=(y);i--)
 5 #define ll long long
 6 #define VI vector<int>
 7 using namespace std;
 8 const int N=2e5+5;
 9 int u,v,n,m,Q,top,bit[N]; VI ans,G[N];
10 struct node{
11     int x,y,ty,op,id;
12     node(){}
13     node(int x,int y,int ty,int op,int id):x(x),y(y),ty(ty),op(op),id(id){}
14 }q[N*5];
15 bool cmp(node x,node y){ return x.x<y.x||x.x==y.x&&x.ty<y.ty; }
16 struct Kruskal_rebuild_tree{
17     int cnt,head[N],fa[N],clk,in[N],out[N],f[N][19];
18     struct edge{ int to,nxt; }e[N];
19     void adde(int x,int y){ e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt; }
20     int getfa(int x){ return x==fa[x]?x:fa[x]=getfa(fa[x]); }
21     void dfs(int u,int ty){
22         rep (i,1,18) f[u][i]=f[f[u][i-1]][i-1];
23         in[u]=++clk;
24         for (int i=head[u];i;i=e[i].nxt) f[e[i].to][0]=u,dfs(e[i].to,ty);
25         out[u]=clk;
26     }
27     void build(int ty){
28         cnt=0; rep (x,1,n) fa[x]=x,head[x]=0;
29         if (!ty){
30             per (x,n,1)
31                 for (auto y:G[x])
32                     if (x<y&&getfa(x)!=(y=getfa(y))) adde(x,y),fa[y]=x;
33         } else{
34             rep (x,1,n)
35                 for (auto y:G[x])
36                     if (x>y&&getfa(x)!=(y=getfa(y))) adde(x,y),fa[y]=x;
37         }
38         rep (i,1,n) if (getfa(i)==i) dfs(i,ty);
39     }
40     int qry(int x,int lim,int ty){
41         per (i,18,0)
42             if (f[x][i]&&(!ty?f[x][i]>=lim:f[x][i]<=lim)) x=f[x][i];
43         return x;
44     }
45 }T[2];
46 void add(int x){ for (;x<=n;x+=x&-x) bit[x]++; }
47 int qry(int x){ int s=0; for (;x;x-=x&-x) s+=bit[x]; return s; }
48 VI check_validity(int _n,VI x,VI y,VI s,VI t,VI l,VI r){
49     n=_n; m=x.size(),Q=s.size();
50     rep (i,0,m-1) G[++x[i]].push_back(++y[i]),G[y[i]].push_back(x[i]);
51     T[0].build(0); T[1].build(1);
52     rep (i,1,n) q[++top]=node(T[0].in[i],T[1].in[i],0,0,0);
53     rep (i,0,Q-1){
54         ++s[i],++t[i],++l[i],++r[i];
55         int u=T[0].qry(s[i],l[i],0),v=T[1].qry(t[i],r[i],1);
56         int l1=T[0].in[u],r1=T[0].out[u],l2=T[1].in[v],r2=T[1].out[v];
57         q[++top]=node(r1,r2,1,1,i);
58         if (l1>1) q[++top]=node(l1-1,r2,1,-1,i);
59         if (l2>1) q[++top]=node(r1,l2-1,1,-1,i);
60         if (l1>1&&l2>1) q[++top]=node(l1-1,l2-1,1,1,i);
61     }
62     sort(q+1,q+1+top,cmp); ans.resize(Q);
63     rep (i,1,top)
64         if (!q[i].ty) add(q[i].y); else ans[q[i].id]+=qry(q[i].y)*q[i].op;
65     rep (i,0,Q-1) ans[i]=!!ans[i];
66     return ans;
67 }
View Code

 

posted @ 2018-10-19 23:21  bestfy  阅读(181)  评论(0编辑  收藏