整体二分(51nod 雪之国度)
2017-04-26 10:11
330 查看
雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路。
雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予的能量为Wi。
如果城市u和v之间有一条道路,那么只要此刻雪之女王的能量不小于|Wu-Wv|,这条道路就是安全的。
如果城市u和v之间存在两条没有重复道路的安全路径(其中每一段道路都是安全的),则认为这两座城市之间有着良好的贸易关系。
最近,雪之女王因为情感问题,她的能量产生巨大的波动。为了维持雪之国度的经济贸易,她希望你能帮忙对Q对城市进行调查。
对于第j对城市uj和vj,她希望知道在保证这两座城市之间有着良好贸易关系的前提之下,自己最少需要保持多少的能量。
每一层开始的时候就是最开始的最小生成树,(大于当前要求的边权的只加成树,一定不影响结果)一层以内从左到右不断地插入(边权不断最大),减小复杂度
循环走层,用队列存这一层后面的一分为二(当前每个区间都一份为二),
而每次加边,必然会出现环,uv各自到lca的链上所有点都是双连通了,这个时候按照并查集的思想,把她们的fa都给成lca 那么判断的时候只要findroot之后,fa相同就是双联通了,具体:u,v中比较深的结点和他的fa一起findroot 不一样,就变成她的fa的findroot(链接到一起) 然后u等于他的fa 最后相同为止
雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予的能量为Wi。
如果城市u和v之间有一条道路,那么只要此刻雪之女王的能量不小于|Wu-Wv|,这条道路就是安全的。
如果城市u和v之间存在两条没有重复道路的安全路径(其中每一段道路都是安全的),则认为这两座城市之间有着良好的贸易关系。
最近,雪之女王因为情感问题,她的能量产生巨大的波动。为了维持雪之国度的经济贸易,她希望你能帮忙对Q对城市进行调查。
对于第j对城市uj和vj,她希望知道在保证这两座城市之间有着良好贸易关系的前提之下,自己最少需要保持多少的能量。
题意:
每一条边都有边权,然后每次询问2个点u,v,找到最小的值X,使得所有边权小于等于X的边形成的图中, u v是在一个双连通分量内的tip:
首先考虑建立最小生成树,每次二分边权,加入小于等于这个权值的所有边,然后对所有区间内询问一分为二,一边是再一个双联通分量,那么她真正的答案一定是小于等于当前值的,另一边是不再一个双连通分量里,那么他的真正答案一定是大于等于当前值的。这样就保证了,logm层 每一层总共询问q次就可以了。总复杂度可行每一层开始的时候就是最开始的最小生成树,(大于当前要求的边权的只加成树,一定不影响结果)一层以内从左到右不断地插入(边权不断最大),减小复杂度
循环走层,用队列存这一层后面的一分为二(当前每个区间都一份为二),
而每次加边,必然会出现环,uv各自到lca的链上所有点都是双连通了,这个时候按照并查集的思想,把她们的fa都给成lca 那么判断的时候只要findroot之后,fa相同就是双联通了,具体:u,v中比较深的结点和他的fa一起findroot 不一样,就变成她的fa的findroot(链接到一起) 然后u等于他的fa 最后相同为止
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> #include <cmath> using namespace std; typedef pair<int,int> pii; const int maxn = 1e6+10; const int maxm = 5e6+10; int n,m,Q,w[maxn],pos_edge,fa[maxn],head[maxn],now; int tot,h[maxn],ct,Troot,root[maxn],cir[maxm],ans[maxm],qid[maxm],fa_strong[maxm]; pii qu[maxn]; struct que{ int l; int r; int qul; int qur; }q[maxm],qtmp[maxm]; struct inp{ int u,v,cost,ord; }data[maxm]; bool cmp(inp a, inp b){ return a.cost < b.cost; } void init(){ scanf("%d%d%d",&n,&m,&Q); tot =0; ct = 1; for(int i = 1; i <= n ; i++){ scanf("%d",&w[i]); head[i] = -1; root[i] = i; } for(int i = 1; i <= m ; i++){ scanf("%d%d",&data[i].u,&data[i].v); data[i].cost = max(w[data[i].v]-w[data[i].u],w[data[i].u]-w[data[i].v]); data[i].ord = i; } sort(data+1,data+m+1,cmp); for(int i = 1; i <= Q; i++){ scanf("%d%d",&qu[i].first,&qu[i].second); qid[i] = i; ans[i] = (1<<30); } } int findroot(int x){ return root[x] = (x == root[x])?x:findroot(root[x]); } struct node{ int u,v,next; }edges[maxm]; void add(int u,int v){ edges[tot].v =v;edges[tot].next = head[u];head[u] = tot++; edges[tot].v =u;edges[tot].next = head[v];head[v] = tot++; } void dfs(int x,int root,int step){ h[x] = step; // cout <<"x - "<<x<<endl; for(int k = head[x] ; k != -1 ; k = edges[k].next){ int v = edges[k].v; if(v == root) continue; fa[v] = x; dfs(v,x,step+1); } } void build_tree(){ Troot = 0; for(int i = 1 ; i <= m ; i++){ int x = data[i].u,y = data[i].v; // cout << "u = "<<data[i].u <<" v = "<<data[i].v<<endl; int fx = findroot(x),fy = findroot(y); if(fx != fy){ root[fx] = fy; //cout <<"x = "<<x<<" y = "<<y<<endl; add(x,y); if(!Troot) Troot = x; } else{ cir[ct++] = i; } } dfs(Troot,-1,1); } int find_cir(int x) { return fa_strong[x] = (fa_strong[x] == x ? x : find_cir(fa_strong[x])) ; } void union_cir(int x , int y) { int fx = find_cir(x) ; int fy = find_cir(y) ; fa_strong[fx] = fy ; //printf("fa_see[%d] = %d\n",fx,fy); } int findq(int mid,int ql,int qr){ //cout <<"mid = "<<data[mid].cost<<endl; for(int i = now ; i < ct ;i++){ int u = data[cir[i]].u,v = data[cir[i]].v; if(data[cir[i]].cost > data[cir[mid]].cost){ now = i; break; } // cout <<" u = "<< u <<" h = "<<h[u] <<" v = "<<v<<" h = "<<h[v]<<endl; u= find_cir(u);v = find_cir(v); while(u != v) { if ( h[u] >= h[v] ) { union_cir(u , fa[u]) ; u = find_cir(fa[u]) ; } else { union_cir(v , fa[v]) ; v = find_cir(fa[v]) ; } } } // for(int i = 1 ; i <= n ;i++){ // //find_cir(i); // printf("fa_st[%d] = %d\n",i,fa_strong[i]); // } int bound = ql-1; // cout <<"ql = " <<ql <<" qr = "<<qr<<endl; for(int L = ql , R = qr; L <= R;){ // printf("find_cir(%d) = %d\n",qu[L].first,find_cir(qu[L].first)); //printf("find_cir(%d) = %d\n",qu[L].second,find_cir(qu[L].second)); while(L <= R && find_cir(qu[L].first) == find_cir(qu[L].second) ){ //cout <<"qid = "<<qid[L]<<" u = "<<qu[L].first<<" v = "<<qu[L].second<<endl; bound = L; ans[qid[L]] = min(ans[qid[L]],data[cir[mid]].cost); // cout << "ans = "<<ans[qid[L]]<<endl; L++; } while(L <= R&& find_cir(qu[R].first) != find_cir(qu[R].second) ){ // printf(" L= %d R = %d\n",L,R); R--; } if(L < R){ swap(qu[L],qu[R]); swap(qid[L],qid[R]); // cout <<"qid = "<<qid[L]<<" u = "<<qu[L].first<<" v = "<<qu[L].second<<endl; ans[qid[L]] = min(ans[qid[L]],data[cir[mid]].cost); // cout << "ans ["<<qid[L]<<"] = "<<ans[qid[L]]<<endl; bound = L; L++;R--; } } // cout<<" bon = "<<bound <<endl; return bound; } void sov(){ int lm = 1,rm = ct-1; int top = 0,tail = -1; q[++tail].l = lm; q[tail].r = rm; q[tail].qul = 1; q[tail].qur = Q; for(int i = 1; i <= log2(m) + 1;i++){//O(20) pos_edge = 0;now = 1; //cout <<" the cemh = "<< i<<endl; for(int i = 1; i <= n ; i++) fa_strong[i] = i; int numq = 0; while(top <= tail){ int tmp = (q[top].l+q[top].r)/2; // printf("bound = %d qul = %d qr = %d\n",tmp,q[top].qul,q[top].qur); int bound = findq(tmp,q[top].qul,q[top].qur); if(q[top].l <= tmp-1 && q[top].qul <= bound){ qtmp[numq].l =q[top].l; qtmp[numq].r = tmp-1; qtmp[numq].qul = q[top].qul; qtmp[numq++].qur = bound; } if(tmp+1 <= q[top].r && bound +1 <= q[top].qur){ qtmp[numq].l =tmp+1; qtmp[numq].r =q[top].r; qtmp[numq].qul=bound+1; qtmp[numq++].qur= q[top].qur; } top++; } tail = -1;top = 0; for(int i = 0 ; i< numq ;i++) q[++tail] = qtmp[i]; } } void print_tree(){ for(int i = 1; i <= n ; i++){ printf("fa[%d] = %d\n",i,fa[i]); } for(int i = 1 ;i < ct ;i++) printf("cir[%d] u = %d v = %d\n",i,data[cir[i]].u,data[cir[i]].v); } void print(){ for(int i = 1 ; i <= Q ; i++){ if(ans[i] == (1<<30)) printf("infinitely\n"); else printf("%d\n",ans[i]); } } int main(){ init(); build_tree(); //print_tree(); sov(); print(); } /* 7 12 5 3 2 4 1 3 5 9 1 2 1 3 2 4 2 5 3 6 6 7 4 6 5 7 4 5 5 6 3 5 3 7 2 7 2 3 1 4 1 3 1 2 10 10 10 53181 9395 30441 197250 86719 81912 128322 192117 95489 115481 7 1 8 5 2 5 10 8 7 10 9 7 1 5 7 6 5 2 5 2 9 3 5 9 3 10 9 6 4 9 6 8 9 3 9 10 7 8 3 7 */
相关文章推荐
- 51 nod 1243 排船的问题(二分)
- 51 nod 1105 第K大的数 二分套二分
- [二分+树状数组]51 Nod 1685——第K大区间2
- 51 nod 1105 (二分)
- [二分+最大流]51 Nod——1757 大灾变
- 【51 Nod 1743】 雪之国度
- 51 NOD 1685 第K大区间2 二分+BIT
- 51 nod 1624 取余最长路 思路:前缀和 + STL(set)二分查找
- 51Nod比赛3总结
- 51 Nod 1005 大数加法【Java大数乱搞,python大数乱搞】
- 【BZOJ 3110】 [Zjoi2013]K大数查询 整体二分+树状数组区间修改
- 51 Nod 1284 2 3 5 7的倍数(容斥原理)
- 【BZOJ1901】Zju2112 Dynamic Rankings【树状数组套主席树 / 整体二分】
- [BZOJ3110][ZJOI2013]K大数查询(整体二分)
- [BZOJ2738]矩阵乘法(整体二分)
- POJ 2104 K-th Number【整体二分 + 树状数组】
- 【编辑距离问题】 51 nod 1183 编辑距离
- 51nod 1133 不重叠的线段
- 2017 暑假艾教集训 day10 (补zoj2112带修改的第k大)整体二分
- BZOJ.2527.[POI2011]MET-Meteors(整体二分)