hdu 5420 Victor and Proposition(强连通+线段树建图)
来源:互联网 发布:选择网络项目的标准 编辑:程序博客网 时间:2024/05/23 02:03
题意:给出一棵树,每个点都给一个x,d,代表它和x这个点以及以下深度差小于d的点都有一条有向边,求互相可达的u,v对数。
做法:可以很容易发觉如果我们把点连好然后直接找强连通分量,然后答案就是每个强连通分量大小x*(x-1)/2之和。
但是因为点有10000个,边极限可以出到n^2个的。所以我们得简化边的个数。先处理出dfs序,保存一下每个点子树的dfs序范围,可以发现,x以及它之下深度小于d的点其实在x子树的dfs序范围里的,我们如果能把这些点按照深度排序,自然就能得到连续的想要的点,基于这个思想。我们考虑对dfs序建立线段树。区间[l,r]的vector代表的dfs序标号为l,r范围内的点,这些点是个二元组,除了是谁还得保存下深度,按之前所说我们把它们按照深度排序,我们把这些排序后的点建新的点来建图类似这样 1<—2 <— 3 <—4,再把这些新的点与原来它代表的点连边,这样的话,如果我想要的d范围最大到3(由于排序了,可以二分找),那么我就跟3连一条边,这样就小于d的点也都连上了。
至于限制条件是必须在x的子树dfs序范围内这个问题,我们可以通过类似线段树区间更新的方式来解决。由于有了线段树,任何dfs区间一定是由不超过logn个区间组合得到,所以就按照刚才的方式递归建边即可。
最后再来算一下空间和时间。我们要新建的点数等于线段树中每个vector的size和。假设某一层为i,那么它要存的点个数是2^(dep-i)个(dep是最大深度),这一层点的个数是2^i个,两者相乘就是2^dep个,即n个,也就是说每一层需要n的空间,树高为logn,所以点数就是o(nlogn)的,边数的话,由于我们需要把这些点之间连边,以及每个新建的点要和原来连边,所以还要乘一个2。
由于子树每个区间都是有序的,我们可以用归并排序,所以建树复杂度o(nlogn),tarjan复杂度o(n+m) = o(n+nlogn)所以总复杂度o(nlogn)。
PS:由于本弱是仔细研读了昂神的代码才理解的。所以写的比较像来着。另。merge竟然比我手写的归并要快。这是为啥。。
AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdlib>#include<stack>#include<queue>#include<set>#include<map>#include<cmath>#include<ctime>#include<string.h>#include<string>#include<sstream>#include<bitset>using namespace std;#define ll __int64#define ull unsigned __int64#define eps 1e-8#define NMAX 1000000000#define MOD (1<<30)#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define PI acos(-1)template<class T>inline void scan_d(T &ret){ char c; int flag = 0; ret=0; while(((c=getchar())<'0'||c>'9')&&c!='-'); if(c == '-') { flag = 1; c = getchar(); } while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar(); if(flag) ret = -ret;}const int maxn = 100000+10;const int maxm = 100000*30+10;struct node{ int dep,pos; node(){} node(int _d, int _p):dep(_d),pos(_p){} bool operator < (const node &t) const { if(dep != t.dep) return dep < t.dep; return pos < t.pos; }};int head[maxm],ecnt;struct Edge{ int v,next;}e[maxm<<1];void add_edge(int u, int v){ e[ecnt].v = v; e[ecnt].next = head[u]; head[u] = ecnt++;}int st[maxn],ed[maxn],dep[maxn],dfs_clock,n,nct;int a[maxn];void dfs(int u, int d){ st[u] = ++dfs_clock; a[dfs_clock] = u; dep[u] = d; for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].v; dfs(v,d+1); } ed[u] = dfs_clock;}vector<node>v[maxn<<2];int beg[maxn<<2];void combin(vector<node> &x, vector<node> &y, vector<node> &z){ int sz1 = x.size(), sz2 = y.size(); int p = 0, p1 = 0, p2= 0; while(p1 < sz1 || p2 < sz2) { if(p1 == sz1 || (p2 != sz2 && y[p2] < x[p1])) z[p++] = y[p2++]; else z[p++] = x[p1++]; }}void build(int l, int r, int rt){ v[rt].resize(r-l+1); if(l == r) { v[rt][0] = node(dep[a[l]],a[l]); n++; add_edge(n,a[l]); beg[rt] = n; return; } int mid = l+r >> 1; build(lson); build(rson);// combin(v[rt<<1],v[rt<<1|1],v[rt]); merge(v[rt<<1].begin(),v[rt<<1].end(),v[rt<<1|1].begin(),v[rt<<1|1].end(),v[rt].begin()); beg[rt] = n+1; for(int i = 1; i < r-l+1; i++) add_edge(n+i+1,n+i); for(int i = 0; i < r-l+1; i++) add_edge(n+i+1,v[rt][i].pos); n += r-l+1;}void update(int L, int R, int x, int d, int l, int r, int rt){ if(L <= l && R >= r) { int pos = lower_bound(v[rt].begin(), v[rt].end(), node(d+1,0))-v[rt].begin()-1; if(pos >= 0) add_edge(x,beg[rt]+pos); return; } int mid = l+r >> 1; if(L <= mid) update(L,R,x,d,lson); if(R > mid) update(L,R,x,d,rson);}int pre[maxm],lowlink[maxm],sum[maxm],scc_cnt;bool sccno[maxm];stack<int>S;void dfs(int u){ pre[u] = lowlink[u] = ++dfs_clock; S.push(u); for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].v; if(!pre[v]) { dfs(v); lowlink[u] = min(lowlink[u],lowlink[v]); } else if(!sccno[v]) { lowlink[u] = min(lowlink[u],pre[v]); } } if(lowlink[u] == pre[u]) { ++scc_cnt; while(1) { int x = S.top(); S.pop(); sccno[x] = 1; sum[scc_cnt] += x <= nct; if(x == u) break; } }}void find_scc(){ dfs_clock = scc_cnt = 0; memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); memset(sum,0,sizeof(sum)); for(int i = 1; i <= nct; i++) if(!pre[i]) dfs(i); ll ans = 0; for(int i = 1; i <= scc_cnt; i++) ans += (ll)sum[i]*(sum[i]-1)/2; printf("%I64d\n",ans);}int main(){#ifdef GLQ freopen("input.txt","r",stdin);// freopen("o.txt","w",stdout);#endif int _t; scanf("%d",&_t); while(_t--) { scanf("%d",&n); nct = n; memset(head,-1,sizeof(head)); ecnt = 0; for(int i = 2; i <= n; i++) { int v; scanf("%d",&v); add_edge(v,i); } dfs_clock = 0; dfs(1,0); memset(head,-1,sizeof(head)); ecnt = 0; build(1,nct,1); for(int i = 1; i <= nct; i++) { int x,d; scanf("%d%d",&x,&d); update(st[x],ed[x],i,dep[x]+d,1,nct,1); } find_scc(); } return 0;}
- hdu 5420 Victor and Proposition 线段树建图+强连通分量
- hdu 5420 Victor and Proposition(强连通+线段树建图)
- 【HDU】5420 Victor and Proposition【SCC+线段树】
- hdu 5419 Victor and Toys 线段树成段更新
- 【强连通】 HDU 4685 Prince and Princess
- hdu 5417 Victor and Machine
- hdu 5417 Victor and Machine
- HDU 5417 Victor and Machine
- HDU-5417Victor and Machine
- hdu 5417 Victor and Machine
- hdu 5419 Victor and Toys
- hdu 5417 Victor and Machine
- hdu 5418 Victor and World
- hdu 5418 Victor and World
- hdu 5417 Victor and Machine
- HDU 5419 Victor and Toys
- HDU 5421 Victor and String
- hdu 4685 Prince and Princess(最大匹配+强连通)
- HDU 2523 hash排序
- 设置某一个Activity为单例模式无法接收到onActivityResult
- package.path和package.cpath
- Unity3D NGUI屏幕摇杆
- Android Overview Screen -- 概览界面
- hdu 5420 Victor and Proposition(强连通+线段树建图)
- HDU 1872 排序
- Ubuntu Server配置wireless连接WPA2网络(interfaces)
- 连连看游戏的实现
- 当tomcat已启动,但打不开tomcat主页
- TCO 2015 2D
- Leetcode #131 Palindrome Partitioning
- 安卓命令写入图片,微信相册中拿不到
- 【小熊刷题】Validate Binary Search Tree <含recursion>