题目
思路
不难想到这样一种思路,每次将边权最大的一条边的两个端点分到不同集合内。
我们先将边排序,然后用并查集进行判断,就有了 的算法,显然不够好。
接下来这个想法就惊为天人了——由于并查集最多连接 条边,所以这 条边就足以确定并查集的结构。我们只存这些有用的边,最后我们把作为答案的那条边也存下来——这是为了便于代码实现。
用线段树来维护,每个区间都存储这至多 条边,并且按照权值从大到小排序。区间合并可以依靠归并排序的思想,并且使用并查集检查,所以建树是 的。
查询的时候仍然可以利用归并排序呢。所以复杂度就是 的。
总复杂度 。不过建树的复杂度跑不满。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int_;
inline int_ readint(){
int_ a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
template < class T >
void getMax(T&a,const T&b){
if(a < b) a = b;
}
const int MaxM = 1000005;
const int MaxN = 1005;
int n; // 点的数量
namespace UFS{
int fa[MaxN], val[MaxN];
void init(){
for(int i=1; i<=n; ++i)
fa[i] = i, val[i] = 0;
}
int find(int a){
if(fa[a] == a) return a;
int root = find(fa[a]);
val[a] ^= val[fa[a]];
return fa[a] = root;
}
int combine(int a,int b){
int x = find(a), y = find(b);
if(x == y) // already connected
if(val[a]^val[b])
return 1; // 什么也不发生
else return 0; // odd cycle!
fa[x] = y; // add an edge
val[x] = val[a]^val[b]^1;
return 2; // 连接了两个连通块
}
};
struct Edge{
int from, to, val;
Edge(int F=0,int T=0,int V=0){
from = F, to = T, val = V;
}
} e[MaxM];
/** @brief 两个关于边的序列,合并为新序列 */
void hebing(vector< int > &v,
vector< int > &v1,
vector< int > &v2){
int p = 0, len1 = v1.size();
int q = 0, len2 = v2.size();
int len = len1+len2; v.resize(len);
while(p < len1 || q < len2){
if(p < len1 && (q >= len2 ||
e[v1[p]].val > e[v2[q]].val))
v[p+q] = v1[p], ++ p;
else v[p+q] = v2[q], ++ q;
}
UFS::init();
int delta = 0; // 往前推一点点
for(int i=0,llb; i+delta<len; ++i){
v[i] = v[i+delta];
llb = UFS::combine(e[v[i]].from,e[v[i]].to);
if(llb == 0){ // 有奇环了
len = i+1+delta;
break; // 最多就到这里了
}
if(llb == 1) // 啥也没有,农民傻了
++ delta, -- i;
}
v.resize(len -= delta);
}
int m; // 线段树的长度:边的数量
vector< int > v[MaxM<<1|1];
int __id(int l,int r){ return (l+r)|(l!=r); }
void build(int l=1,int r=m){
if(l == r){
v[__id(l,r)].resize(1);
v[__id(l,r)][0] = l;
return ;
}
int t = (l+r)>>1;
build(l,t), build(t+1,r);
hebing(v[__id(l,r)],
v[__id(l,t)],v[__id(t+1,r)]);
}
void query(int ql,int qr,
vector< int > &res,
int l=1,int r=m){
if(ql <= l && r <= qr){
res = v[__id(l,r)]; return ;
}
int t = (l+r)>>1;
if(qr <= t) return query(ql,qr,res,l,t);
if(t < ql) return query(ql,qr,res,t+1,r);
vector< int > tmp[2];
query(ql,qr,tmp[0],l,t);
query(ql,qr,tmp[1],t+1,r);
hebing(res,tmp[0],tmp[1]);
}
vector< int > res;
int main(){
n = readint(), m = readint();
int q = readint();
for(int i=1; i<=m; ++i){
e[i].from = readint();
e[i].to = readint();
e[i].val = readint();
}
build();
while(q --){
int l = readint();
int r = readint();
query(l,r,res); UFS::init();
bool notAny = true;
for(int i=0,len=res.size(); i<len; ++i)
if(UFS::combine(e[res[i]].from,
e[res[i]].to) == 0)
notAny = false;
if(!notAny)
printf("%d\n",e[res.back()].val);
else printf("-1\n");
}
return 0;
}