HDU 4694 Important Sisters
来源:互联网 发布:lte网络优化很垃圾 编辑:程序博客网 时间:2024/05/18 03:53
题目大意:
给你N个点和M条边的有向图,其中第N个点是源点
让你求每个节点#I关于点#N的关键点的编号和
解题思路:
这题是2013 Multi-University Training Contest 9的题目,官方题解是用bitset或者floyd乱搞
然而丁神告诉我们这题是一题裸的Lengauer_Tarjan算法,具体算法见Tarjan论文,有详细的伪代码
附上丁神的模板
Lengauer-Tarjan algorithm的作用是求出dominator tree,这棵树上的每一个节点都是其儿子的idom
明显我们求出这棵树之后,原题要求的就是每个节点到根的路径上的各节点的编号和
O(MlogM)的算法和O(ma(N,M))的优化在于EVAL和LINK函数
succ数组存的是原图
fa数组存的是i结点的先驱,在dfs生成树上的父亲
dfn数组存的是i结点的新编号,redfn存的是i结点的原编号
prod数组存根据dfs重新排序之后的图
semi数组存半必经点的新编号,表示的是在dfs树上,节点i的祖先中,可以通过一系列的非树边走到i的,深度最小的祖先,i的直系父亲也可以是半必经点
bucket数组存的是,以i作为半必经点的点
idom数组存的是,i的immediate dominator
anc数组:step3里把点都先当成孤立的森林,然后每访问一个点,就将他和他父亲连边,anc数组存的就是结点的父 亲,并且compress用了类似并查集的方式压缩,以此更快速地找到深度最小的祖先
<pre name="code" class="cpp">#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <vector>#include <queue>#include <deque>#include <utility>#include <map>#include <set>#include <cctype>#include <climits>#include <stack>#include <cmath>#include <bitset>#include <numeric>#include <functional>using namespace std;vector<int> succ[50010], prod[50010], bucket[50010], dom_t[50010];int semi[50010], anc[50010], idom[50010], best[50010], fa[50010];int dfn[50010], redfn[50010];int timestamp;void dfs(int now){ dfn[now] = ++timestamp; redfn[timestamp] = now; anc[timestamp] = idom[timestamp] = 0; semi[timestamp] = best[timestamp] = timestamp; int sz = succ[now].size(); for(int i = 0; i < sz; ++i) { if(dfn[succ[now][i]] == -1) { dfs(succ[now][i]); fa[dfn[succ[now][i]]] = dfn[now]; } prod[dfn[succ[now][i]]].push_back(dfn[now]); }}void compress(int now){ if(anc[anc[now]] != 0) { compress(anc[now]); if(semi[best[now]] > semi[best[anc[now]]]) best[now] = best[anc[now]]; anc[now] = anc[anc[now]]; }}int eval(int now){ if(anc[now] == 0) return now; compress(now); return best[now];}void debug(){ for(int i=timestamp;i>1;i--) cout<<redfn[i]<<" "<<redfn[anc[i]]<<" "<<redfn[fa[i]]<<endl; cout<<"---------------------"<<endl;}void lengauer_tarjan(int n){ memset(dfn, -1, sizeof dfn); memset(fa, -1, sizeof fa);//memset(anc, 0, sizeof anc);//memset(idom, 0, sizeof idom);//for(int i = 0; i <= n; ++i)//best[i] = semi[i] = i; timestamp = 0; dfs(n); fa[1] = 0; for(int w = timestamp; w > 1; --w) { if(fa[w] == -1) continue; int sz = prod[w].size(); for(int i = 0; i < sz; ++i) { int u = eval(prod[w][i]); if(semi[w] > semi[u]) semi[w] = semi[u]; } debug(); bucket[semi[w]].push_back(w); anc[w] = fa[w]; if(fa[w] == 0) continue; sz = bucket[fa[w]].size(); for(int i = 0; i < sz; ++i) { int u = eval(bucket[fa[w]][i]); if(semi[u] < fa[w]) idom[bucket[fa[w]][i]] = u; else idom[bucket[fa[w]][i]] = fa[w]; } bucket[fa[w]].clear(); } for(int w = 2; w <= n; ++w) { if(fa[w] == -1) continue; if(idom[w] != semi[w]) idom[w] = idom[idom[w]]; } idom[1] = 0; for(int i = timestamp; i > 1; --i) { if(fa[i] == -1) continue; dom_t[idom[i]].push_back(i); }}long long ans[50010];void get_ans(int now){ ans[redfn[now]] += redfn[now]; int sz = dom_t[now].size(); for(int i = 0; i < sz; ++i) { ans[redfn[dom_t[now][i]]] += ans[redfn[now]]; get_ans(dom_t[now][i]); }}void MAIN(int n, int m){ for(int i = 0; i <= n; ++i) succ[i].clear(), prod[i].clear(), bucket[i].clear(), dom_t[i].clear(); for(int i = 0, u, v; i < m; ++i) { scanf("%d%d", &u, &v); succ[u].push_back(v); } lengauer_tarjan(n); memset(ans, 0, sizeof ans); get_ans(1); for(int i = 1; i <= n; ++i) printf("%I64d%c", ans[i], i == n ? '\n' :' ');}int main(){ int n, m; while(scanf("%d%d", &n, &m) > 0) MAIN(n, m); return 0;}
O(ma(N,M))模板来源丁神
</pre><pre name="code" class="cpp">// whn6325689//Mr.Phoebe//http://blog.csdn.net/u013007900#include <algorithm>#include <iostream>#include <iomanip>#include <cstring>#include <climits>#include <complex>#include <fstream>#include <cassert>#include <cstdio>#include <bitset>#include <vector>#include <deque>#include <queue>#include <stack>#include <ctime>#include <set>#include <map>#include <cmath>#include <functional>#include <numeric>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;typedef long long ll;typedef long double ld;typedef pair<ll, ll> pll;typedef complex<ld> point;typedef pair<int, int> pii;typedef pair<pii, int> piii;typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))#define mp(x,y) make_pair(x,y)#define pb(x) push_back(x)#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))#define eps 1e-9#define PI acos(-1.0)#define INF 0x3f3f3f3f#define LLINF 1LL<<62template<class T>inline bool read(T &n){ T x = 0, tmp = 1; char c = getchar(); while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar(); if(c == EOF) return false; if(c == '-') c = getchar(), tmp = -1; while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar(); n = x*tmp; return true;}template <class T>inline void write(T n){ if(n < 0) { putchar('-'); n = -n; } int len = 0,data[20]; while(n) { data[len++] = n%10; n /= 10; } if(!len) data[len++] = 0; while(len--) putchar(data[len]+48);}//-----------------------------------//Auther:winoros ding//input : succ//output dom_t and idom redfn//notice that the index i in dom_t[i] and dom_t[i][j] is the vertex's timestamp in dfs//hence you need redfn[i] to find the original vertex//o(mlogm) where m is the number of edges//UPD:new version is o(m|á(m, n)), the previous version is in commentconst int vector_num=50000; //max number of verticesvector<int> succ[vector_num+10], prod[vector_num+10], bucket[vector_num+10], dom_t[vector_num+10];int semi[vector_num+10], anc[vector_num+10], idom[vector_num+10], best[vector_num+10], fa[vector_num+10];int dfn[vector_num+10], redfn[vector_num+10];int child[vector_num+10], size[vector_num+10];int timestamp;void dfs(int now){ dfn[now] = ++timestamp; redfn[timestamp] = now; anc[timestamp] = idom[timestamp] = child[timestamp] = size[timestamp] = 0; semi[timestamp] = best[timestamp] = timestamp; int sz = succ[now].size(); for(int i = 0; i < sz; ++i) { if(dfn[succ[now][i]] == -1) { dfs(succ[now][i]); fa[dfn[succ[now][i]]] = dfn[now]; } prod[dfn[succ[now][i]]].push_back(dfn[now]); }}void compress(int now){ if(anc[anc[now]] != 0) { compress(anc[now]); if(semi[best[now]] > semi[best[anc[now]]]) best[now] = best[anc[now]]; anc[now] = anc[anc[now]]; }}inline int eval(int now){ if(anc[now] == 0) return now; else { compress(now); return semi[best[anc[now]]] >= semi[best[now]] ? best[now] : best[anc[now]]; }}inline void link(int v, int w){ int s = w; while(semi[best[w]] < semi[best[child[w]]]) { if(size[s] + size[child[child[s]]] >= 2*size[child[s]]) { anc[child[s]] = s; child[s] = child[child[s]]; } else { size[child[s]] = size[s]; s = anc[s] = child[s]; } } best[s] = best[w]; size[v] += size[w]; if(size[v] < 2*size[w]) swap(s, child[v]); while(s != 0) { anc[s] = v; s = child[s]; }}void lengauer_tarjan(int n) // n is the vertices' number{ memset(dfn, -1, sizeof dfn); memset(fa, -1, sizeof fa); timestamp = 0; dfs(n); fa[1] = 0; for(int w = timestamp; w > 1; --w) { int sz = prod[w].size(); for(int i = 0; i < sz; ++i) { int u = eval(prod[w][i]); if(semi[w] > semi[u]) semi[w] = semi[u]; } bucket[semi[w]].push_back(w); //anc[w] = fa[w]; link operation for o(mlogm) version link(fa[w], w); if(fa[w] == 0) continue; sz = bucket[fa[w]].size(); for(int i = 0; i < sz; ++i) { int u = eval(bucket[fa[w]][i]); if(semi[u] < fa[w]) idom[bucket[fa[w]][i]] = u; else idom[bucket[fa[w]][i]] = fa[w]; } bucket[fa[w]].clear(); } for(int w = 2; w <= timestamp; ++w) { if(idom[w] != semi[w]) idom[w] = idom[idom[w]]; } idom[1] = 0; for(int i = timestamp; i > 1; --i) { if(fa[i] == -1) continue; dom_t[idom[i]].push_back(i); }}long long ans[50010];void get_ans(int now){ ans[redfn[now]] += redfn[now]; int sz = dom_t[now].size(); for(int i = 0; i < sz; ++i) { ans[redfn[dom_t[now][i]]] += ans[redfn[now]]; get_ans(dom_t[now][i]); }}void init(int n, int m){ for(int i=0; i<=n; i++) succ[i].clear(), prod[i].clear(), bucket[i].clear(), dom_t[i].clear(); CLR(ans,0);}int main(){ int n, m; while(read(n)&&read(m)) { init(n,m); for(int i=0,u,v; i<m; i++) { read(u), read(v); succ[u].push_back(v); } lengauer_tarjan(n); get_ans(1); for(int i=1; i<=n; i++) printf("%I64d%c", ans[i], i == n ? '\n' :' '); } return 0;}
0 0
- HDU 4694 Important Sisters
- HDU 4694 Important Sisters Lengauer_Tarjan算法
- HDU 4694 Important Sisters【支配树】
- HDU 4694: Important Sisters(支配树)
- 【23.91%】【hdu 4694】Important Sisters("支NMLGB配树"后记)(支配树代码详解)
- [HDU4694]Important Sisters
- hdu4694 Important Sisters 支配树
- HDU4694 支配树裸题 Important Sisters
- HDU4694:Important Sisters(支配树DominatorTree)
- important
- important
- !important
- !important
- Team of sisters
- UVA 12571 Brother & Sisters!
- 词汇-important
- important information
- flash important
- Android内存分析和调优(下)
- Knight's Tour骑士游历问题(C语言实现)
- Linux命令学习:mkdir
- 验证图是否相似
- linux上删除所有的无效文件链接
- HDU 4694 Important Sisters
- pdns 错误解决[备忘]
- ArrayList与数组
- 修改服务器3389远程登录端口
- Spring事务配置的五种方式及事务传播
- MongoDB Windows配置手册
- Android SDK包下载分享
- 前端开发技巧杂谈
- Oracle查询不重复字段的所有列