1. 程式人生 > >滅絕樹題集

滅絕樹題集

滅絕樹   ??? 什麼沙雕東西啊   百度好像沒有相關介紹啊  研究了一發別人程式碼 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;
}