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