• uoj407 【IOI2018】狼人


    link

    题意:

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

    $n,qleq  2 imes 10^5,mleq 4 imes 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}(nlog 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
  • 相关阅读:
    【转】用户权限管理经典篇
    [转]提高精简框架集程序的性能
    迷你电话本
    Serial Communication via RS232 Port
    wxWidgets类列表(2.6.4)
    Parallel Port Programming (Part 2): with Visual C++
    [转]WINCE的编程忠告
    宽字符处理函数函数与普通函数对照表
    [转]C# 解析配置文件内容 System.Configuration
    Parallel Port Programming (Part 1): with C
  • 原文地址:https://www.cnblogs.com/bestFy/p/9819838.html
Copyright © 2020-2023  润新知