有一个由M 条电缆连接的 N 个站点组成的网络。为了防止垄断,由 C 个公司控制所有的电缆,规定任何公司不能控制连接同一个站点的两条以上的电缆(可以控制两条)。同时规定,每个公司不能有多余的电缆,所谓的多余,是指属于同一个公司的电缆不能形成环。
在运作过程中,不同公司之间会进行电缆买卖。请你写一个程序判断买卖是否合法。
有一个由M 条电缆连接的 N 个站点组成的网络。为了防止垄断,由 C 个公司控制所有的电缆,规定任何公司不能控制连接同一个站点的两条以上的电缆(可以控制两条)。同时规定,每个公司不能有多余的电缆,所谓的多余,是指属于同一个公司的电缆不能形成环。
在运作过程中,不同公司之间会进行电缆买卖。请你写一个程序判断买卖是否合法。
输入第一行有4个由空格隔开的整数 N,M,C和 T。N(1≤N≤ 8 000)表示站点数,M(0≤M≤100 000)表示连接站点的电缆数。C(1≤C≤ 100)表表示公司数量,T 表示电缆买卖次
数。后面有M行,每行三个整数Sj1,Sj2和Kj,表示连接站点Sj1和Sj2(1≤Sj1< Sj2 ≤ n)的电缆属于Kj(1≤Kj≤C)公司拥有,任意两个站点只有一条直接相连的电缆,输入状态合法。最后T(0≤T≤100 000)行,每行三个整数 Si1, Si2和 Ki,表示 Ki公司想购买站点Si1和Si2之间的电缆。
输出共 T行,表示处理的结果,有以下几种可能的结果:
1、“No such cable.” 两个站点间没有电缆。
2、 “Already owned.” 电缆己经是 Ki 公司控制。
3、 “Forbidden: monopoly.” Ki 公司己经控制了两条连接 Si1 或 Si2 的电缆。
4、 “Forbidden: redundant.” Ki 公司控制的线路会出现环。
5、 “Sold.” 可以买卖。
题解:这道题是学长出的互测题的第二题,被学长贴标签为EASY&&LCT裸题。当然我这么傻逼,当时还不会LCT,只能打打并查集,骗了60分。。。。。
啊啊啊!!终于会LCT 了,于是想要水掉这道题,结果昨天晚上查错,先是用近一个小时找到了一个手残错误,然后过了样例,结果自己出的第一组小样例,就被卡了 T_T
最后发现问题出在判断Already owned.上,然后傻逼的我询问fye学姐,如何判断x,y 直接有直连边啊,学姐云:为什么要在lct 中判断,你直接map一下不就好了。 我石化。。。
然后就改成了这个样子。
#include<iostream> #include<cstdio> #include<cstring> #include<map> #include<algorithm> #define C 120 #define N 8003 using namespace std; map<int,int> mp; int n,m,c,t; int fa[C][N],col[N][C],ch[C][N][3],rev[C][N],top,st[N]; int next[C][N]; int isroot(int x,int k) { return ch[k][fa[k][x]][1]!=x&&ch[k][fa[k][x]][0]!=x; } int get(int x,int k) { return ch[k][fa[k][x]][1]==x; } void pushdown(int x,int k) { if (rev[k][x]&&x) { swap(ch[k][x][0],ch[k][x][1]); if (ch[k][x][0]) rev[k][ch[k][x][0]]^=1; if (ch[k][x][1]) rev[k][ch[k][x][1]]^=1; rev[k][x]=0; } } void rotate(int x,int k) { int y=fa[k][x];int z=fa[k][y]; int which=get(x,k); if (!isroot(y,k)) ch[k][z][ch[k][z][1]==y]=x; ch[k][y][which]=ch[k][x][which^1]; fa[k][ch[k][y][which]]=y; ch[k][x][which^1]=y; fa[k][y]=x; fa[k][x]=z; } void splay(int x,int k) { top=0; st[++top]=x; for (int i=x;!isroot(i,k);i=fa[k][i]) st[++top]=fa[k][i]; for (int i=top;i>0;i--) pushdown(st[i],k); while (!isroot(x,k)) { int y=fa[k][x]; if (!isroot(y,k)) rotate(get(x,k)==get(y,k)?y:x,k); rotate(x,k); } } void access(int x,int k) { int t=0; while (x) { splay(x,k); ch[k][x][1]=t; t=x; x=fa[k][x]; } } void rever(int x,int k) { access(x,k); splay(x,k); rev[k][x]^=1; } void link(int k,int x,int y) { rever(x,k); fa[k][x]=y; splay(x,k); } int find(int x,int k) { access(x,k); splay(x,k); while (ch[k][x][0]) x=ch[k][x][0]; return x; } void cut(int x,int y,int k) { rever(x,k); access(y,k); splay(y,k); ch[k][y][0]=fa[k][x]=0; } int main() { scanf("%d%d%d%d",&n,&m,&c,&t); mp.clear(); for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if (x>y) swap(x,y); link(z,x,y); col[x][z]++; col[y][z]++; int a=(x-1)*8000+y; mp[a]=z;//map 映射,因为一共不超过8000个点,所以 <span style="font-family: Arial, Helvetica, sans-serif;">(x-1)*8000+y 相当于对点对进行编号,然后就可以在之后通过映射查询边的信息了,长知识啊</span> } for (int i=1;i<=t;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if (x>y) swap(x,y); bool p=false; int a=(x-1)*8000+y; if (mp[a]) { if (mp[a]==z) { printf("Already owned.\n"); continue; } if (col[x][z]>=2||col[y][z]>=2)//col 数字用来计算一个点不同颜色的出度 { printf("Forbidden: monopoly.\n"); continue; } if (find(x,z)==find(y,z)) { printf("Forbidden: redundant.\n"); continue; } cut(x,y,mp[a]); col[x][mp[a]]--; col[y][mp[a]]--; link(z,x,y); col[x][z]++; col[y][z]++; mp[a]=z; printf("Sold.\n"); } else { printf("No such cable.\n"); continue; } } }