2055. Urban Geography
Time limit: 2.0 second
Memory limit: 128 MB
Memory limit: 128 MB
Android Vasya prepares a project in Urban geography. The aim of the project is to improve the infrasructure of the city he lives in.
Now the city consists of
n districts, some of which are connected by roads. Using these roads one can get from any district to any other district of the city by car. Vasya thinks that such big amount of roads makes citizens use their own cars instead of walking or cycling. He wants to close as many roads for cars as possible and turn them into boulevards. Of course, Vasya wants to keep the possibility to get from any district to any other district of the city by car using roads.
Now citizens pay for using roads, and prices for different roads may vary very much. Vasya thinks that leaving open some expensive and some cheap roads at the same time is not a good idea beacuse it can increase social tension in the city. That’s why he wants to minimize the price spread between the most expensive and the cheapest roads. Help Vasya choose the roads to keep open.
Input
The first line contains integers
n и
m that are the number of city districts and roads correspondingly (2 ≤
n ≤ 50 000;
n − 1 ≤
m ≤ 50 000). The next
m lines contain triples of integers
a
i,
b
i and
c
i, meaning that between the city districts
a
i and
b
i there is a road with the price
c
i (1 ≤
a
i,
b
i ≤
n;
a
i ≠
b
i; 1 ≤
c
i ≤ 10
9). There can be several roads between two districts.
Output
In the only line output the sequence of integers — numbers of the roads which should be kept open in the city. The roads are numbered as they appear in the input data. If there are several solutions, output any of them.
Samples
input | output |
---|---|
3 3 1 2 1 2 3 3 3 1 4 | 2 3 |
4 5 1 2 1 2 3 1 1 3 2 1 4 2 2 4 1 | 1 2 5 |
Problem Author: Nikita Burlakov
Problem Source: Ural Sport Programming Championship 2015
Problem Source: Ural Sport Programming Championship 2015
构建一棵树,是的最长边-最短边最小。
用动态树维护mst。更新最小距离。
动态树的建发:
对每个点建立一个结点。对每条边建立一个结点。加边<u,v>的时候,如果u,v在同一棵树上
把u,v,access到同一个splay中,找到边最小的结点x,cut(x,v),cut(x,u)
把u,v分别变成自己所在树的根,然后对于边建立点x,link(x,u),link(x,v)即可。
动态树要维护的是树中边的权值。
44case T了一天了。实在没办法,换一种方法做吧,下次回来做这题
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define maxn 400007
#define inf 1000000000
int cnt = 0;
struct Node{
Node *fa,*ch[2];
bool root,rev;
int val,mval;
Node(){}
Node* init(int v,Node *f){
fa = f;
ch[0] = ch[1] = f;
root = true;
val = mval = v;
rev = false;
return this;
}
void update(){
mval = val;
if(ch[0]->mval < mval)
mval = ch[0]->mval;
if(ch[1]->mval < mval)
mval = ch[1]->mval;
}
void update_rev(){
if(val == inf + 10000000)return ;
rev = !rev;
swap(ch[0],ch[1]);
}
void pushdown(){
if(rev){
ch[0]->update_rev();
ch[1]->update_rev();
rev = false;
}
}
void rotate(){
Node *f = fa, *ff = f->fa;
int t = (f->ch[1] == this);
if(f->root)
root = true, f->root = false;
else ff->ch[ff->ch[1] == f] = this;
fa = ff;
f->ch[t] = ch[t^1];
ch[t^1]->fa = f;
ch[t^1] = f;
f->fa = this;
f->update();
}
void push(){
if(!root) fa->push();
pushdown();
}
void splay(){
push();
Node *f, *ff;
while(!root){
f = fa,ff = f->fa;
if(!f->root)
if((ff->ch[1]==f)&&(f->ch[1] == this)) f->rotate();
else rotate();
rotate();
}
update();
}
};
Node pool[maxn];
Node *nil,*tree[maxn];
void init(){
cnt = 1;
nil = tree[0] = pool;
nil->val = nil -> mval = inf+10000000;
}
//将x到树根的路径并成一条path******
Node *access(Node *x){
Node *y = nil;
while(x != nil){
x->splay();
x->ch[1]->root = true;
(x->ch[1] = y)->root = false;
x->update();
y = x;
x = x->fa;
}
return y;
}
//将结点x变成树根******
void be_root(Node *x){
//cout<<x->val-inf<<endl;
access(x);
x->splay();
x->update_rev();
//update_rev(x);
}
//将x连接到结点f上******
void link(Node *x, Node *f){
be_root(x);
x->fa = f;
}
//将x,y分离******
void cut(Node *x,Node *y){
be_root(x);
access(x);
y->splay();
y->fa = nil;
}
Node *findminNode(Node *x){
if(x->val <= x->ch[0]->mval && x->val <= x->ch[1]->mval)
return x;
if(x->ch[0]->mval < x->ch[1]->mval)
return findminNode(x->ch[0]);
return findminNode(x->ch[1]);
}
Node *findRoot(Node *x){
if(x->ch[0] == nil) return x;
return findRoot(x->ch[0]);
}
struct Edge{
int u,v,w;
Edge (){}
int getn(){
int n = 0;
char x;
while(1){
x = getchar();
if(x == ' ' || x == '\n') return n;
n = n*10+x-'0';
}
}
void init(){
u = getn();
v = getn();
w = getn();
}
};
Edge edge[maxn];
int fa[100007];
int find(int u){
if(fa[u] == u) return u;
return fa[u] = find(fa[u]);
}
multiset<int>haha;
int comp1(int a,int b){
return edge[a].w < edge[b].w;
}
int id[100007];
int main(){
//freopen("j.in","r",stdin);
//freopen("jl.out","w",stdout);
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
haha.clear();
//edge.clear();
Edge e;
getchar();
for(int i = 0;i < m; i++){
edge[i].init();
if(edge[i].u == edge[i].v){
m--;
i--;
continue;
}
id[i] = i;
}
sort(id,id+m,comp1);
init();
for(int i = 1;i <= n;i++)
tree[i] = pool[cnt++].init(inf+i,nil);
int num = n,ans=1000000000,be,en;
Node *x,*y,*z;
for(int i = 0;i < m; i++){
int u = edge[id[i]].u,v = edge[id[i]].v,w=edge[id[i]].w;
haha.insert(w);
z = pool[cnt++].init(w,nil);
be_root(tree[u]);
x = access(tree[v]);
y = findRoot(x);
if(tree[u] == y){
x = findminNode(x);
cut(x,tree[u]);
cut(x,tree[v]);
haha.erase(haha.find(x->val));
num++;
}
link(tree[u],z);
link(tree[v],z);
num--;
if(num == 1){
int mval = *haha.begin();
if(w - mval < ans){
ans = w - mval;
be = mval;
en = w;
}
}
}
num = n;
for(int i = 0;i <= n; i++)
fa[i] = i;
for(int i = 0;i < m; i++){
e = edge[i];
if(e.w >= be && e.w <= en){
int f1 = find(e.u);
int f2 = find(e.v);
if(f1 != f2){
fa[f1] = fa[f2];
if(num != n) putchar(' ');
printf("%d",i+1);
num--;
}
}
}
printf("\n");
}
return 0;
}