灭绝树题集

灭绝树   ??? 什么沙雕东西啊   百度好像没有相关介绍啊  研究了一发别人代码 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;
}

  

posted @ 2018-11-17 16:29  wang9897  阅读(594)  评论(0编辑  收藏  举报