[ONTAK2010]Peaks
题目大意:
一个图上有$n(n\leq100000)$个带权点,$m(m\leq500000)$条带权边。有$q(q\leq500000)$组询问,每次询问从点$v$出发,只经过权值小于等于$x$的边能到达的点中,权值第$k$大的点权。
思路:
离线处理每个询问。将询问和边分别按权值排序,处理到当前询问时,将权值小于等于$x$的边加入到图中。用权值线段树维护每个连通块的权值。点的联通情况用并查集维护(相当于Kruskal),权值线段树直接合并。时间复杂度$O(n\log n+m\log m+q\log q+q\log n)$。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=100001,M=500000,Q=500000; 12 int h[N],tmp[N],ans[Q]; 13 struct Edge { 14 int u,v,w; 15 bool operator < (const Edge &another) const { 16 return w<another.w; 17 } 18 }; 19 Edge e[M]; 20 struct Query { 21 int v,x,k,id; 22 bool operator < (const Query &another) const { 23 return x<another.x; 24 } 25 }; 26 Query q[Q]; 27 struct DisjointSet { 28 int anc[N]; 29 int find(const int &x) { 30 return x==anc[x]?x:anc[x]=find(anc[x]); 31 } 32 void reset(const int &n) { 33 for(register int i=1;i<=n;i++) anc[i]=i; 34 } 35 void merge(const int &x,const int &y) { 36 anc[find(y)]=find(x); 37 } 38 bool same(const int &x,const int &y) { 39 return find(x)==find(y); 40 } 41 }; 42 DisjointSet s; 43 class SegmentTree { 44 private: 45 struct Node { 46 int val; 47 Node *left,*right; 48 Node(const int &v):val(v),left(NULL),right(NULL) {} 49 }; 50 void modify(Node *&p,const int &b,const int &e,const int &x) { 51 p=new Node(1); 52 if(b==e) return; 53 const int mid=(b+e)>>1; 54 if(x<=mid) modify(p->left,b,mid,x); 55 if(x>mid) modify(p->right,mid+1,e,x); 56 } 57 public: 58 Node *root[N]; 59 void reset(const int &n) { 60 for(register int i=1;i<=n;i++) { 61 modify(root[i],1,tmp[0],h[i]); 62 } 63 } 64 void merge(Node *&p1,Node *const &p2) { 65 if(!p1) { 66 p1=p2; 67 return; 68 } 69 if(!p2) return; 70 p1->val+=p2->val; 71 merge(p1->left,p2->left); 72 merge(p1->right,p2->right); 73 delete p2; 74 } 75 int query(const Node *const &p,const int &b,const int &e,const int &k) const { 76 if(p->val<k) return -1; 77 if(b==e) return b; 78 const int mid=(b+e)>>1; 79 if(!p->right) return query(p->left,b,mid,k); 80 if(k<=p->right->val) return query(p->right,mid+1,e,k); 81 return query(p->left,b,mid,k-p->right->val); 82 } 83 }; 84 SegmentTree t; 85 inline void add_edge(const Edge &e) { 86 if(s.same(e.u,e.v)) return; 87 t.merge(t.root[s.find(e.u)],t.root[s.find(e.v)]); 88 s.merge(e.u,e.v); 89 } 90 int main() { 91 const int n=getint(),m=getint(),cnt_q=getint(); 92 for(register int i=1;i<=n;i++) { 93 tmp[i]=h[i]=getint(); 94 } 95 std::sort(&tmp[1],&tmp[n]+1); 96 tmp[0]=std::unique(&tmp[1],&tmp[n]+1)-&tmp[1]; 97 for(register int i=1;i<=n;i++) { 98 h[i]=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,h[i])-&tmp[0]; 99 } 100 for(register int i=0;i<m;i++) { 101 const int u=getint(),v=getint(),w=getint(); 102 e[i]=(Edge){u,v,w}; 103 } 104 std::sort(&e[0],&e[m]); 105 for(register int i=0;i<cnt_q;i++) { 106 const int v=getint(),x=getint(),k=getint(); 107 q[i]=(Query){v,x,k,i}; 108 } 109 std::sort(&q[0],&q[cnt_q]); 110 s.reset(n); 111 t.reset(n); 112 for(register int i=0,p=0;i<cnt_q;i++) { 113 while(p<m&&e[p].w<=q[i].x) add_edge(e[p++]); 114 ans[q[i].id]=t.query(t.root[s.find(q[i].v)],1,tmp[0],q[i].k); 115 } 116 for(register int i=0;i<cnt_q;i++) { 117 printf("%d\n",~ans[i]?tmp[ans[i]]:-1); 118 } 119 return 0; 120 }