灭绝树题集
灭绝树 ??? 什么沙雕东西啊 百度好像没有相关介绍啊 研究了一发别人代码 woc 这不是拓扑+倍增吗
回归正题
灭绝树是什么: 灭绝树是一种数据结构 它能解决 DAG图上关键点的问题 即这颗树的性质是 如果v是u的祖先节点 v灭绝了 u也活不下去了 ->灭绝树
怎么构造灭绝树: 我们考虑是一个DAG图 拓扑排序后 连向他的节点均加入到树中 当加入这个节点时 只需要把这个节点挂到lca(对这点连边的节点)下面 然后就能保证其祖先节点gg 他的子树节点也会gg的性质
构造方法: 边跑拓扑的时候 把入度为0的点 加入到树中 倍增维护网上跳的情况
例题1.
2815: [ZJOI2012]灾难
对于A被B吃 则A->B 然后题目保证DAG 直接灭绝树即可
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=3e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int du[MAXN]; vector<int>vec[MAXN],v1[MAXN]; queue<int>que; int f[MAXN][21],dep[MAXN],size[MAXN]; int Lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); int tmp=dep[u]-dep[v]; for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i]; if(u==v)return u; for(int i=20;i>=0;i--){ if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i]; } return f[u][0]; } void dfs(int x){ size[x]=1; for(int i=0;i<v1[x].size();i++){dfs(v1[x][i]);size[x]+=size[v1[x][i]];} } int main(){ int n=read(); inc(i,1,n){ int t; while(scanf("%d",&t)!=EOF){ if(!t)break; add(t,i);du[i]++;vec[i].pb(t); } } inc(i,1,n)if(!du[i])add(n+1,i),du[i]++,vec[i].pb(n+1); que.push(n+1);f[n+1][0]=0;dep[n+1]=1; while(!que.empty()){ int t=que.front();que.pop(); link(t){ du[j->t]--; if(!du[j->t]){ que.push(j->t); int lca=t; for(int k=0;k<vec[j->t].size();k++)lca=Lca(lca,vec[j->t][k]); f[j->t][0]=lca;dep[j->t]=dep[lca]+1;v1[lca].pb(j->t); for(int k=1;k<=20;k++)f[j->t][k]=f[f[j->t][k-1]][k-1]; } } } dfs(n+1); inc(i,1,n)printf("%d\n",size[i]-1); }
例题2.
codeforces757F. Team Rocket Rises Again
题解:跑出最短路图 然后灭绝树处理
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=2e5+10; const double eps=1e-8; #define ll long long const ll inf=1e18; using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<2],*h[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } typedef struct node{ int v;ll d; friend bool operator<(node aa,node bb){return aa.d>bb.d;} }node; ll dis[MAXN]; priority_queue<node>que; int n,m,s; void dij(){ inc(i,1,n)dis[i]=inf; dis[s]=0;que.push((node){s,0}); while(!que.empty()){ node t=que.top();que.pop(); link(t.v){ if(dis[j->t]>dis[t.v]+j->v){ dis[j->t]=dis[t.v]+j->v; que.push((node){j->t,dis[j->t]}); } } } } vector<int>vec[MAXN],v1[MAXN]; int du[MAXN],f[MAXN][21],dep[MAXN]; queue<int>q; int Lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); int tmp=dep[u]-dep[v]; for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i]; if(u==v)return u; for(int i=20;i>=0;i--){ if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i]; } return f[u][0]; } int size[MAXN]; void dfs(int x){ size[x]=1; link(x)dfs(j->t),size[x]+=size[j->t]; } int main(){ n=read();m=read();s=read(); int u,v,k; inc(i,1,m)u=read(),v=read(),k=read(),add(u,v,k),add(v,u,k); dij(); for(int i=1;i<=n;i++){ link(i){ if(dis[i]+j->v==dis[j->t])vec[i].pb(j->t),du[j->t]++,v1[j->t].pb(i); } } memset(h,0,sizeof(h));o=e; q.push(s);f[s][0]=0;dep[s]=1; while(!q.empty()){ int t=q.front();q.pop(); for(int i=0;i<vec[t].size();i++){ du[vec[t][i]]--; if(!du[vec[t][i]]){ q.push(vec[t][i]); v=vec[t][i]; int lca=t; for(int j=0;j<v1[v].size();j++)lca=Lca(lca,v1[v][j]); f[v][0]=lca;dep[v]=dep[lca]+1;add(lca,v,0); for(int j=1;j<=20;j++)f[v][j]=f[f[v][j-1]][j-1]; } } } dfs(s); int maxx=0; inc(i,1,n)if(i!=s)maxx=max(maxx,size[i]); printf("%d\n",maxx); }
例题3.
101741L. Increasing Costs
题解:跑出最短路树 然后把边作点拆边构成DAG图 类似例2处理即可
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=4e5+10; const double eps=1e-8; #define ll long long const ll inf=1e18; using namespace std; struct edge{int t,v,id;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y,int vul,int id){o->t=y;o->v=vul;o->next=h[x];o->id=id;h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } ll dis[MAXN]; typedef struct node{ int v;ll d; friend bool operator<(node aa,node bb){return aa.d>bb.d;} }node; priority_queue<node>que; int n,m; void dij(){ inc(i,1,n)dis[i]=inf; dis[1]=0;que.push((node){1,0}); while(!que.empty()){ node t=que.top();que.pop(); link(t.v){ if(dis[j->t]>t.d+j->v){ dis[j->t]=t.d+j->v;que.push((node){j->t,dis[j->t]}); } } } } typedef struct Edge{ int u,v,id; }Edge; Edge EDge[MAXN<<1]; int du[MAXN]; int f[MAXN<<1][21],dep[MAXN<<1]; queue<int>q; vector<int>vec[MAXN<<1],v1[MAXN<<1]; int Lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); int tmp=dep[u]-dep[v]; for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i]; if(u==v)return u; for(int i=20;i>=0;i--){ if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i]; } return f[u][0]; } int size[MAXN<<1],ans[MAXN]; void dfs(int x){ if(x<=n)size[x]=1; for(int i=0;i<v1[x].size();i++){ dfs(v1[x][i]); size[x]+=size[v1[x][i]]; } if(x>n)ans[x-n]=size[x]; } int main(){ n=read();m=read(); int u,v,k; inc(i,1,m)u=read(),v=read(),k=read(),add(u,v,k,i),add(v,u,k,i); dij();int cnt=0; inc(i,1,n){ link(i){ if(dis[j->t]==dis[i]+j->v)EDge[++cnt]=(Edge){i,j->t,j->id}; } } memset(h,0,sizeof(h));o=e; for(int i=1;i<=cnt;i++){ add(EDge[i].u,EDge[i].id+n,0,0);du[EDge[i].id+n]++; vec[EDge[i].id+n].pb(EDge[i].u); add(EDge[i].id+n,EDge[i].v,0,0);du[EDge[i].v]++; vec[EDge[i].v].pb(EDge[i].id+n); } q.push(1);f[1][0]=0;dep[1]=1; while(!q.empty()){ int t=q.front();q.pop(); link(t){ du[j->t]--; if(!du[j->t]){ q.push(j->t); int lca=t; for(int k=0;k<vec[j->t].size();k++){ lca=Lca(lca,vec[j->t][k]); } f[j->t][0]=lca;dep[j->t]=dep[lca]+1;v1[lca].pb(j->t); for(int k=1;k<=20;k++)f[j->t][k]=f[f[j->t][k-1]][k-1]; } } } dfs(1); inc(i,1,m)printf("%d\n",ans[i]); return 0; }