首页 > 代码库 > 传纸条(scrip)

传纸条(scrip)

传纸条(scrip)

题目背景

Awson是某国际学校信竞组的一只菜鸡。每次竞赛考试都只能垫底。终于有一天,他决定不再苟活,发挥他的人脉优势,准备在一次竞赛考试时传纸条作弊。

题目描述

他预先知道了考试时机房人数N(1<=N<=10000),自己编号为1,并且由于他十分地交际,所以能够确保所有人能为他提供答案。为了传递纸条,他会开动脑筋,想出M(0<=M<=100000)种单个可行方案。每种单个方案不一定与自己有关,因为他可以间接地从别人那获得他人的答案。每种方案已知三个数据U,V,C(1<=U,V<=N;1<=C<=1000000)表示从U到V有一种可行方案,其代价为C,且方案是双向的,即U可以传纸条给V且V也可以传纸条给U。由于作弊是高风险的事情,他决定考前预谋好总的方案。他想知道:

(1)团结所有人(即每个人都能够互相联系)所需要的最小代价和。

(2)基于(1),他会给出Q(1<=Q<=10000)个询问,每个询问有三个数据OPT,X,Y(OPT=0 or 1;1<=X,Y<=N),询问有两种类型:

OPT=0时:询问X到Y的路径上单个最大代价的值;

OPT=1时:询问X到Y的路径上的总代价。

但如果不存在(1)方案,即他不能团结起所有人,那么他这场考试就又失败了,他就会无限地堕落下去,请输出”OVER!”(半角字符,不含引号),并忽略之后的询问。

由于他还有重要的事情要做,所以这个任务交给了你,怎么样,应该不难吧?

(请阅读样例及其说明以便更好地了解题意)

输入输出格式

输入格式:

第1行:两个整数N,M

第2~M+1行:每行三个整数Ui,Vi,Ci

第M+2行:一个整数Q

第M+3~M+Q+2行:每行三个整数OPTi,Xi,Yi

输出格式:

有两种情况:

若不存在(1)方案,输出共1行,第1行为”OVER!”(半角字符,不含引号);

若存在,输出共Q+1行,第1行一个整数,表示团结所有人所需要的最小代价和,第2~Q+1行每行一个整数,代表每个询问的结果。

输入输出样例

输入样例:

7 12

1 4 994

1 2 999

1 2 1

1 3 2

1 6 998

2 4 4

2 5 3

3 7 5

3 6 6

4 5 995

5 7 996

6 7 997

10

1 1 4

0 1 4

1 1 7

0 1 6

1 4 6

0 5 7

1 2 4

0 3 5

1 6 7

0 4 5

输出样例:

21

5

4

7

6

13

5

4

3

11

4

说明

样例解释:

路径1<—>4上,所有的单个方案代价分别为1,4。则对于第一组询问(1,1,4),代价和为1+4=5;对于第二组询问(0,1,4),其路径上单个最大的代价为4。
团结所有人的方案在图中用红色表示,则所需要的最小代价和为1+2+3+4+5+6=21。

其余同理。

数据规模:

30%的数据:1<=N,Q<=1000

50%的数据:1<=N,Q<=5000

100%的数据:1<=N,Q<=10000,0<=M<=10×N,所有数据保证不会超过长整型(C++中的int),保证每种单个方案的代价各不相同。

题解:

 

正解Kruskal+LCA

 

用Kruskal求出图的最小生成树,转化为有根树之后套LCA模板。

 

本来想强制在线的,但数据太水你会发现就算退化成链每次直接遍历都不会超时。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long lol;
lol n,m,l,mmax,ans,tot;//n<=10000;m<=100000;l<=10000
struct student{lol u,v,c;}a[100005];
bool cmp(const student a,const student b){return a.c<b.c;}//输入边和排序
lol head[10001],size=1;
struct node{lol next,to,dis;}edge[200005];
void putin(lol from,lol to,lol dis){size++;edge[size].to=to;edge[size].next=head[from];edge[size].dis=dis;head[from]=size;}
void in(lol from,lol to,lol dis){putin(from,to,dis);putin(to,from,dis);}//建树 
lol father[10005];
lol find(lol x){if(father[x]==x)return x;else return father[x]=find(father[x]);}//并查集
lol fa[10005][25],vis[10005],depth[10005],dis[10005][25],dist[10005][25];
void dfs(lol r)
{
    vis[r]=1;lol i;
    for(i=head[r];i!=-1;i=edge[i].next)
    {
        lol y=edge[i].to;
        if(!vis[y]){depth[y]=depth[r]+1;fa[y][0]=r;dist[y][0]=dis[y][0]=edge[i].dis;dfs(y);}
    }
}
void make()
{
    lol i,j,len=log2(n);
    for(j=1;j<=len;j++)
    {
        for(i=1;i<=n;i++)
        {
            dis[i][j]=max(dis[fa[i][j-1]][j-1],dis[i][j-1]);
            dist[i][j]=dist[fa[i][j-1]][j-1]+dist[i][j-1];
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}
void RMQ(lol x,lol y)
{
    mmax=0;ans=0;
    lol i,op=log2(n);
    if(depth[x]<depth[y])swap(x,y);
    for(i=op;i>=0;i--)
    if(depth[fa[x][i]]>=depth[y])
    {
        mmax=max(mmax,dis[x][i]);
        ans+=dist[x][i];
        x=fa[x][i];
    }
    if(x!=y)
    {
        for(i=op;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
        {
            mmax=max(mmax,max(dis[x][i],dis[y][i]));
            ans+=dist[x][i]+dist[y][i];
            x=fa[x][i];y=fa[y][i];
        }
        ans+=dist[x][0]+dist[y][0];
        mmax=max(mmax,max(dis[x][0],dis[y][0]));
        x=fa[x][0];y=fa[y][0];
    }
    return;
}
lol gi()
{
    lol ans=0,f=1;
    char i=getchar();
    while(i<0||i>9){if(i==-)f=-1;i=getchar();}
    while(i>=0&&i<=9){ans=ans*10+i-0;i=getchar();}
    return ans*f;
}
int main()
{
    freopen("scrip.in","r",stdin);
    freopen("scrip.out","w",stdout);
    lol i;
    n=gi();m=gi();
    memset(head,-1,sizeof(head));
    for(i=1;i<=n;i++)father[i]=i;//初始化并查集
    for(i=1;i<=m;i++){a[i].u=gi();a[i].v=gi();a[i].c=gi();}//输入边 
    sort(a+1,a+m+1,cmp);//排序
    for(i=1;i<=m;i++)
    {
        lol p=find(a[i].u),q=find(a[i].v);
        if(p!=q){father[p]=q;in(a[i].u,a[i].v,a[i].c);tot+=a[i].c;}
    }
    printf("%lld\n",tot);
    depth[1]=1;dfs(1);make();
    l=gi();
    for(i=1;i<=l;i++)
    {
        lol s=gi(),u=gi(),v=gi();RMQ(u,v);
        if(s==0)printf("%lld\n",mmax);//单个最大
        else if(s==1)printf("%lld\n",ans);//求路径和
    }
    return 0;
}

 

传纸条(scrip)