P4899 [IOI2018] werewolf 狼人 题解
因为我记忆力不好,经常遇到之前做过的题一下子想不起来,所以打算基本上给每个比较有意思的题写题解,同时造福后代。
这是werewolf,它是furry,很可爱
题意:一张无向图,点有点权,每次询问从
思路:从起点找到所有可以到达的点权大于等于
考虑 kruskal 重构树,关于 kruskal 重构树
构建一个小顶堆(人走),然后从起点往上跳到最后一个权值大于等于
两个堆分别建一个 dfn 序列
代码
#include<bits/stdc++.h> inline int read(){ char ch=getchar();int x=0,f=1; for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48); return x*f; } const int N=4e5+10; int n,m,q; struct Edge{int u,v,w;}ed[N]; inline bool cmp_per(Edge a,Edge b){return a.w>b.w;} inline bool cmp_wolf(Edge a,Edge b){return a.w<b.w;} struct Ktree{ int dfn[N],fa[N],st[25][N],head[N],val[N],dfn_cnt=0,e_cnt=0,lf[N],rf[N]; struct edge{int v,nex;}e[N]; inline void add(int u,int v){e[++e_cnt]={v,head[u]};head[u]=e_cnt;} inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} inline void dfs(int x){ lf[x]=++dfn_cnt;dfn[dfn_cnt]=x; for(int i=1;i<=20;++i)st[i][x]=st[i-1][st[i-1][x]]; for(int i=head[x];i;i=e[i].nex)dfs(e[i].v); rf[x]=dfn_cnt; } inline void build(int type){ for(int i=1;i<=2*n-1;++i)fa[i]=i; for(int i=1;i<=m;++i)ed[i].w=type?std::min(ed[i].u,ed[i].v):std::max(ed[i].u,ed[i].v); if(type)std::stable_sort(ed+1,ed+m+1,cmp_per);else std::stable_sort(ed+1,ed+m+1,cmp_wolf); int node_tot=n+1; for(int i=1;i<=m&&node_tot<=2*n-1;++i){ int u=ed[i].u,v=ed[i].v,w=ed[i].w; int fu=find(u),fv=find(v); if(fu!=fv){ val[node_tot]=w; add(node_tot,fu),add(node_tot,fv); st[0][fu]=st[0][fv]=fa[fu]=fa[fv]=node_tot; node_tot++; } } dfs(node_tot-1); } inline int get(int x,int v,int type){ for(int i=20;i>=0;--i){ if(type&&st[i][x]&&val[st[i][x]]>=v)x=st[i][x]; if(!type&&st[i][x]&&val[st[i][x]]<=v)x=st[i][x]; } return x; } }Per,Wolf; int root[N],cnt; struct Tree{int siz,ls,rs;}t[N<<5]; inline void update(int p){t[p].siz=t[t[p].ls].siz+t[t[p].rs].siz;} inline void insert(int last,int p,int x,int l,int r){ if(l==r){t[p].siz=t[last].siz+1;return;} int mid=(l+r)>>1;t[p]=t[last]; if(x<=mid)insert(t[last].ls,t[p].ls=++cnt,x,l,mid); else insert(t[last].rs,t[p].rs=++cnt,x,mid+1,r); update(p); } inline int query(int last,int p,int x,int y,int l,int r){ if(l>=x&&r<=y){return t[p].siz-t[last].siz;} int mid=(l+r)>>1,ans=0; if(x<=mid)ans+=query(t[last].ls,t[p].ls,x,y,l,mid); if(y>mid)ans+=query(t[last].rs,t[p].rs,x,y,mid+1,r); return ans; } int main(){ // freopen("in.in","r",stdin),freopen("out.out","w",stdout); std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0); n=read(),m=read(),q=read(); int len=2*n-1; for(int i=1;i<=m;++i) ed[i].u=read()+1,ed[i].v=read()+1; Per.build(1),Wolf.build(0); for(int i=1;i<=Wolf.dfn_cnt;++i){ root[i]=root[i-1]; int x=Wolf.dfn[i]; if(x<=n)insert(root[i-1],root[i]=++cnt,Per.lf[x],1,len); } for(int i=1;i<=q;++i){ int u=read(),v=read(),l=read(),r=read(); u++,v++,l++,r++; int start=Per.get(u,l,1),end=Wolf.get(v,r,0); if(query(root[Wolf.lf[end]-1],root[Wolf.rf[end]],Per.lf[start],Per.rf[start],1,len)) std::cout<<1<<'\n'; else std::cout<<0<<'\n'; } }
分类:
解题报告
标签:
Kruskal 重构树
, 主席树/可持久化线段树
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】