hdu 4964 支配树

支配树裸题:求支配集

不太会写带权并查集,调了好久

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 using namespace std;
  7 #define maxn 100020
  8 #define inf 0x3f3f3f3f
  9
 10 typedef long long ll;
 11 struct node{
 12     int next,to;
 13     void cl(){
 14         next = 0 , to = 0;
 15     }
 16 }e[maxn * 2],e2[maxn * 2];
 17 int head[maxn],head2[maxn],cnt;
 18 int n,m,fa[maxn],val[maxn],vis[maxn];
 19 int idom[maxn],semi[maxn],pnt[maxn],dfn[maxn],id[maxn],dfstime;
 20 ll ans[maxn];
 21 vector <int> ques[maxn];
 22
 23 inline void clear(){
 24     for (int i = 1 ; i <= cnt ; i++) e[i].cl();
 25     for (int i = 1 ; i <= n ; i++) head[i] = 0;
 26     cnt = 0;
 27     for (int i = 1 ; i <= n ; i++) ques[i].clear();
 28     for (int i = 1 ; i <= n ; i++) ans[i] = 0 , id[i] = pnt[i] = fa[i] = idom[i] = semi[i] = val[i] = vis[i] = 0 , dfn[i] = inf;
 29     dfstime = 0;
 30 }
 31 inline void adde(int x,int y){
 32     e[++cnt].to = y;
 33     e2[cnt].to = x;
 34     e[cnt].next = head[x];
 35     e2[cnt].next = head2[y];
 36     head[x] = cnt;
 37     head2[y] = cnt;
 38 }
 39 inline void adde2(int x,int y){
 40     e[++cnt].to = y;
 41     e[cnt].next = head[x];
 42     head[x] = cnt;
 43 }
 44 void dfs(int x){
 45     vis[x] = 1, dfn[x] = ++dfstime, id[dfstime] = x;
 46     for (int i = head[x] ; i ; i = e[i].next){
 47         if ( !vis[e[i].to] ) pnt[e[i].to] = x , dfs(e[i].to);
 48     }
 49 }
 50 int getfa(int x){
 51     if ( fa[x] == x ) return x;
 52     int a = getfa(fa[x]);
 53     if ( semi[val[x]] > semi[val[fa[x]]] ) val[x] = val[fa[x]];
 54     return fa[x] = a;
 55 }
 56 inline void merge(int x,int y){
 57     if ( getfa(x) != getfa(y) ) fa[y] = x;
 58 }
 59 void dfs(int x,int fa,ll cur){
 60     cur += (ll)x;
 61     ans[x] = cur;
 62     for (int i = head[x] ; i ; i = e[i].next){
 63         if ( e[i].to == fa ) continue;
 64         dfs(e[i].to,x,cur);
 65     }
 66 }
 67 void calc(){
 68     for (int i = 1 ; i <= cnt ; i++) e[i].cl(), e2[i].cl();
 69     for (int i = 1 ; i <= n ; i++) head[i] = head2[i] = 0;
 70     cnt = 0;
 71     for (int i = 1 ; i <= n ; i++){
 72         if ( idom[i] && idom[i] != i ) adde2(idom[i],i) , adde2(i,idom[i]);
 73     }
 74     dfs(n,0,0);
 75 }
 76 void solve(){
 77     semi[0] = inf;
 78     //val[x]表示到x的祖先中semi最小的点的编号
 79     //semi[x]表示x的半支配点的dfn
 80     for (int i = 1 ; i <= n ; i++) fa[i] = i , semi[i] = inf;
 81     for (int i = dfstime ; i ; i--){
 82         int x = id[i];
 83         for (int j = 0 ; j < ques[x].size() ; j++){
 84             int y = ques[x][j];
 85             getfa(y);
 86             if ( semi[val[y]] < dfn[x] ) idom[y] = val[y];
 87         }
 88         for (int j = head2[x] ; j ; j = e2[j].next){
 89             if ( dfn[x] > dfn[e2[j].to] ) semi[x] = min(semi[x],dfn[e2[j].to]);
 90             else{
 91                 getfa(e2[j].to);
 92                 semi[x] = min(semi[x],semi[val[e2[j].to]]);
 93             }
 94         }
 95         if ( pnt[x] ) semi[x] = min(semi[x],dfn[pnt[x]]);
 96         if ( x == n ) semi[x] = 1;
 97         if ( semi[x] < semi[val[x]] ) val[x] = x;
 98         for (int j = head[x] ; j ; j = e[j].next)
 99             if ( pnt[e[j].to] == x ) merge(x,e[j].to);
100         ques[id[semi[x]]].push_back(x);
101     }
102     for (int i = 1 ; i <= dfstime ; i++){
103         int x = id[i];
104         if ( idom[x] ) idom[x] = idom[idom[x]]; //idom[x]最初存的是x到其semi路径上的semi最小值的点
105         else idom[x] = id[semi[x]];
106     }
107 //    for (int i = 1 ; i <= n ; i++) cout<<idom[i]<<" ";
108 //    cout<<endl;
109     calc();
110     for (int i = 1 ; i <= n ; i++){
111            printf("%lld",ans[i]);
112         if ( i < n ) printf(" ");
113     }
114     printf("\n");
115 }
116 int main(){
117     freopen("input.txt","r",stdin);
118     while ( ~scanf("%d %d",&n,&m) ){
119         clear();
120         for (int i = 1 ; i <= m ; i++){
121             int x,y;
122             scanf("%d %d",&x,&y);
123             adde(x,y);
124         }
125         dfs(n);
126         solve();
127     }
128 }
时间: 2024-11-04 17:12:23

hdu 4964 支配树的相关文章

HDU.4694.Important Sisters(支配树)

HDU \(Description\) 给定一张简单有向图,起点为\(n\).对每个点求其支配点的编号和. \(n\leq 50000\). \(Solution\) 支配树. 还是有点小懵逼. 不管了,说不定会讲,反正以后再说. https://blog.csdn.net/litble/article/details/83019578 有图的:https://blog.csdn.net/VioletSu/article/details/81041954 有题的:https://blog.csd

hdu 6604 DAG上的支配树(灭绝树)

http://acm.hdu.edu.cn/showproblem.php?pid=6604 很裸的支配树/灭绝树题 一般图的tarjan算法的话,先建立,反向图,然后建立一个超级源点,然后连到几个起点,跑支配树就行 可惜太慢...过不去 #pragma GCC optimize("Ofast") #include<bits/stdc++.h> #define endl '\n' #define ll long long #define ull unsigned long

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

HDU 4417 划分树+二分

题意:有n个数,m个询问(l,r,k),问在区间[l,r] 有多少个数小于等于k. 划分树--查找区间第k大的数.... 利用划分树的性质,二分查找在区间[l,r]小于等于k的个数. 如果在区间第 i 大的数tmp>k,则往下找,如果tmp<k,往上找. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #incl

康复计划#4 快速构造支配树的Lengauer-Tarjan算法

本篇口胡写给我自己这样的老是证错东西的口胡选手 以及那些想学支配树,又不想啃论文原文的人- 大概会讲的东西是求支配树时需要用到的一些性质,以及构造支配树的算法实现- 最后讲一下把只有路径压缩的并查集卡到$O(m \log n)$上界的办法作为小彩蛋- 1.基本介绍 支配树 DominatorTree 对于一个流程图(单源有向图)上的每个点$w$,都存在点$d$满足去掉$d$之后起点无法到达$w$,我们称作$d$支配$w$,$d$是$w$的一个支配点. 支配$w$的点可以有多个,但是至少会有一个.

hdu 4964 Emmet(模拟)

题目链接:hdu 4964 Emmet 题目大意: 给定语句,按照语法翻译并输出. 解题思路:用递归模拟文法分析,主要注意几点: 括号并且的情况:(fuck)(you) 括号嵌套的情况:((fuck.you)) 优先输出id,然后是class(题目中有说) 乘法的部分:fuck*2>you*3 (每次执行fuck时,you的地方同样被执行了3次) 其他跑出样例基本没问题,具体看代码. #include <cstdio> #include <cstring> #include

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]