Problem L.超级无敌动态简单树题

野龙新学了动态树 但野王龙嫌这个数据结构太过简单,于是随手对它进行了改进和升级——超级无敌动态简单树诞生了!
为了让后人可以检验自己写的超级无敌动态简单树是否正确,野龙再随手出了一道超级无敌动态简单树的模板题:

在此题中,你需要维护一个共有n个结点的动态森林,支持以下2种操作:

  1. 添加一条边(u,v)。保证u和v在原森林中属于两棵不同的树。(注意这里是“原”森林)
  2. 查询某个结点到结点 1 的最短距离

注意本题中只保证初始状态为合法森林,后续加边可能出现环。

Input

第一行包含一个正整数T,表示数据组数 输入的第 1 行包含 3 个整数n,m,q,依次描述森林的结点数,森林的边数,和操作的次数。
解析来m行,每行3个整数 u,v,w,表示森林在初始状态下有边(u,v),其边权为w。 接下来q行,每行其实有一个整数op,表示操作类型。
-若op=1,后接三个整数u,v,w,表示添加一条边(u,v),其边权为w;
-若op=2,后接一个整数p表示查询结点p到结点1的最短距离。
数据范围:
T<=10
1<m<n<=10000
1<=u,v<=n
1<=q<=50000
0<=w<=1000
保证输入的初始状态描述的一定是一个合法的森林,保证操作1不超过100次

Output

对于每组测试数据, 对于每个op=2的操作输出一行一个整数,表示对应查询操作的答案,
特别地,如果所查询的结点与结点 1不连通,输出-1。

Sample Input

1
9 6 10
1 2 2
1 3 0
3 4 1
5 6 3
5 7 5
7 8 7
2 2
2 7
1 1 6 2
1 1 6 2
1 1 5 6
2 5
1 3 9 20
2 9
1 8 9 2
2 9

Sample Output

2
-1
5
20
19

代码

//慢慢研究吧……
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
int dis[maxn],book[maxn];
int head[maxn],cnt;
const int INF=0x3f3f3f3f;
struct Edge{
    int to,w,next;
}edge[maxn*5+5];
struct node{
    int index,dist;
    friend bool operator < (node a,node b){
        return a.dist>b.dist;
    }
};
priority_queue<node> myq;
void add_edge(int u,int v,int w){
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].to=u;
    edge[cnt].w=w;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
void dijkstra(int n){
    dis[1]=0;
    for(int i=2;i<=n;i++)dis[i]=INF;
    myq.push(node{1,0});
    while(!myq.empty()){
        node x=myq.top();
        myq.pop();
        int u=x.index;
        if(book[u]) continue;
        book[u]=1;
        for(int j=head[u];j;j=edge[j].next){
            if(dis[edge[j].to]>dis[u]+edge[j].w){
                dis[edge[j].to]=dis[u]+edge[j].w;
                myq.push(node{edge[j].to,dis[edge[j].to]});
            }
        }
    }
}
void add(int n){
    int u,v,w;
    scanf("%d %d %d",&u,&v,&w);
    add_edge(u,v,w);
    memset(book,0,sizeof(book));
    dijkstra(n);
}
void get(){
    int p;
    cin>>p;
    if(dis[p]==INF){
        cout<<-1<<endl;
    }else{
        cout<<dis[p]<<endl;
    }
}
void _(int T){
    while(T--){
        int n,m,q;
        cnt=1;
        memset(head,0,sizeof(head));
        for(int i=0;i<maxn*5+5;i++){

        }
        cin>>n>>m>>q;
        memset(book,0,sizeof(book));
        while(m--){
            int u,v,w;
            cin>>u>>v>>w;
            add_edge(u,v,w);
        }
        dijkstra(n);
        while(q--){
            int op;
            scanf("%d",&op);
            switch(op){
                case 1:add(n);break;
                case 2:get();break;
            }
        }
    }
}
int main(){
    int T;cin>>T;
    _(T);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值