传纸条(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; }