Description
有一个由M 条电缆连接的 N 个站点组成的网络。为了防止垄断,由 C 个公司控制所有的电缆,规定任何公司不能控制连接同一个站点的两条以上的电缆(可以控制两条)。同时规定,每个公司不能有多余的电缆,所谓的多余,是指属于同一个公司的电缆不能形成环。
在运作过程中,不同公司之间会进行电缆买卖。请你写一个程序判断买卖是否合法。
Input
输入第一行有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之间的电缆。
Output
输出共 T行,表示处理的结果,有以下几种可能的结果:
1、“No such cable.” 两个站点间没有电缆。
2、 “Already owned.” 电缆己经是 Ki 公司控制。
3、 “Forbidden: monopoly.” Ki 公司己经控制了两条连接 Si1 或 Si2 的电缆。
4、 “Forbidden: redundant.” Ki 公司控制的线路会出现环。
5、 “Sold.” 可以买卖。
Sample Input
4 5 3 5
1 2 1
2 3 1
3 4 2
1 4 2
1 3 3
1 2 3
1 2 3
1 4 3
2 3 3
2 4 3
Sample Output
Sold.
Already owned.
Forbidden: monopoly.
Forbidden: redundant.
No such cable.
分析:
我们可以用一种很暴力的方法:
建C棵LCT,每棵的结点个数是n
(n和C的范围都比较小)
用map记录一下每条边属于哪个公司
这就可以解决:Already owned. /No such cable.
记录点的度数,处理:Forbidden: monopoly.
用LCT维护连通性,回答:Forbidden: redundant.
如果冲破了重重考验,我们就可以:Sold.
tip
用map的判断一定要放在最前面
这样就不会影响Forbidden: redundant. 的回答
make_pair的时候一定是:p=make_pair(min(x,y),max(x,y));
一开始一直WA,原因竟是主程序中手残把 - - 写错
程序中,我把所有的结点都放在了“一起”
有一个getbh函数确定每一棵LCT的结点
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#define pp pair<int,int>
using namespace std;
const int N=800010;
int ch[N][2],pre[N],size[N],du[102][8002];
bool rev[N];
int q[N],m,n,C,T;
pp p1;
map<pp,int> mp;
int getbh(int tree,int bh) {
return (tree-1)*n+bh;
}
int get(int bh)
{
return ch[pre[bh]][0]==bh? 0:1;
}
int isroot(int bh)
{
return ch[pre[bh]][0]!=bh&&ch[pre[bh]][1]!=bh;
}
void update(int bh)
{
if (!bh) return;
size[bh]=1;
if (ch[bh][0]) size[bh]+=size[ch[bh][0]];
if (ch[bh][1]) size[bh]+=size[ch[bh][1]];
}
void push(int bh)
{
if (!bh) return;
if (rev[bh])
{
if (ch[bh][0]) rev[ch[bh][0]]^=1;
if (ch[bh][1]) rev[ch[bh][1]]^=1;
swap(ch[bh][0],ch[bh][1]);
rev[bh]^=1;
}
}
void rotate(int bh)
{
int fa=pre[bh];
int grand=pre[fa];
int wh=get(bh);
if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=bh;
pre[bh]=grand;
ch[fa][wh]=ch[bh][wh^1];
pre[ch[fa][wh]]=fa;
ch[bh][wh^1]=fa;
pre[fa]=bh;
update(fa);
update(bh);
}
void splay(int bh)
{
int top=0;
q[++top]=bh;
for (int i=bh;!isroot(i);i=pre[i]) q[++top]=pre[i];
while (top) push(q[top--]);
for (int fa;!isroot(bh);rotate(bh))
if (!isroot(fa=pre[bh]))
rotate(get(bh)==get(fa)? fa:bh);
}
void expose(int bh)
{
int t=0;
while (bh)
{
splay(bh);
ch[bh][1]=t;
update(bh);
t=bh;
bh=pre[bh];
}
}
void makeroot(int bh)
{
expose(bh);
splay(bh);
rev[bh]^=1;
}
void link(int x,int y)
{
makeroot(x);
pre[x]=y;
}
void cut(int x,int y)
{
makeroot(x);
expose(y); splay(y);
pre[x]=ch[y][0]=0;
}
int find(int x)
{
expose(x);
splay(x);
while (ch[x][0]) x=ch[x][0];
return x;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&C,&T);
int x,y,z;
mp.clear();
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
pp p;
p=make_pair(min(x,y),max(x,y));
mp[p]=z;
link(getbh(z,x),getbh(z,y));
du[z][x]++; du[z][y]++;
}
for (int i=1;i<=T;i++)
{
scanf("%d%d%d",&x,&y,&z);
pp p;
p=make_pair(min(x,y),max(x,y));
if (mp[p]==0)
{
printf("No such cable.\n");
continue;
}
if (mp[p]==z)
{
printf("Already owned.\n");
continue;
}
if (du[z][x]>=2||du[z][y]>=2)
{
printf("Forbidden: monopoly.\n");
continue;
}
if (find(getbh(z,x))==find(getbh(z,y)))
{
printf("Forbidden: redundant.\n");
continue;
}
printf("Sold.\n");
int fro=mp[p];
du[fro][x]--; du[fro][y]--;
du[z][x]++; du[z][y]++;
cut(getbh(fro,x),getbh(fro,y));
link(getbh(z,x),getbh(z,y));
mp[p]=z;
}
return 0;
}
还有一种写法,没有把所有的结点混在一起(但是比较容易写错)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#define pp pair<int,int>
using namespace std;
const int N=8010;
int ch[102][N][2],pre[102][N],du[102][8002];
bool rev[102][N];
int q[N],m,n,C,T;
pp p1;
map<pp,int> mp;
int get(int tree,int bh)
{
return ch[tree][ pre[tree][bh] ][0]==bh? 0:1;
}
int isroot(int tree,int bh)
{
return ch[tree][ pre[tree][bh] ][0]!=bh&&ch[tree][ pre[tree][bh] ][1]!=bh;
}
void push(int tree,int bh)
{
if (!bh) return;
if (rev[tree][bh])
{
if (ch[tree][bh][0]) rev[tree][ch[tree][bh][0]]^=1;
if (ch[tree][bh][1]) rev[tree][ch[tree][bh][1]]^=1;
swap(ch[tree][bh][0],ch[tree][bh][1]);
rev[tree][bh]^=1;
}
}
void rotate(int tree,int bh)
{
int fa=pre[tree][bh];
int grand=pre[tree][fa];
int wh=get(tree,bh);
if (!isroot(tree,fa))
ch[tree][grand][ch[tree][grand][0]==fa? 0:1]=bh;
pre[tree][bh]=grand;
ch[tree][fa][wh]=ch[tree][bh][wh^1];
pre[tree][ch[tree][fa][wh]]=fa;
ch[tree][bh][wh^1]=fa;
pre[tree][fa]=bh;
}
void splay(int tree,int bh)
{
int top=0;
q[++top]=bh;
for (int i=bh;!isroot(tree,i);i=pre[tree][i]) q[++top]=pre[tree][i];
while (top) push(tree,q[top--]);
for (int fa;!isroot(tree,bh);rotate(tree,bh))
if (!isroot(tree,fa=pre[tree][bh]))
rotate(tree,get(tree,bh)==get(tree,fa)? fa:bh);
}
void expose(int tree,int bh)
{
int t=0;
while (bh)
{
splay(tree,bh);
ch[tree][bh][1]=t;
t=bh;
bh=pre[tree][bh];
}
}
void makeroot(int tree,int bh)
{
expose(tree,bh);
splay(tree,bh);
rev[tree][bh]^=1;
}
void link(int tree,int x,int y)
{
makeroot(tree,x);
pre[tree][x]=y;
}
void cut(int tree,int x,int y)
{
makeroot(tree,x);
expose(tree,y); splay(tree,y);
pre[tree][x]=ch[tree][y][0]=0;
}
int find(int tree,int x)
{
expose(tree,x);
splay(tree,x);
while (ch[tree][x][0]) x=ch[tree][x][0];
return x;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&C,&T);
int x,y,z;
mp.clear();
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
pp p;
p=make_pair(min(x,y),max(x,y));
mp[p]=z;
link(z,x,y);
du[z][x]++; du[z][y]++;
}
for (int i=1;i<=T;i++)
{
scanf("%d%d%d",&x,&y,&z);
pp p;
p=make_pair(min(x,y),max(x,y));
if (mp[p]==0)
{
printf("No such cable.\n");
continue;
}
if (mp[p]==z)
{
printf("Already owned.\n");
continue;
}
if (du[z][x]>=2||du[z][y]>=2)
{
printf("Forbidden: monopoly.\n");
continue;
}
if (find(z,x)==find(z,y))
{
printf("Forbidden: redundant.\n");
continue;
}
printf("Sold.\n");
int fro=mp[p];
du[fro][x]--; du[fro][y]--;
du[z][x]++; du[z][y]++;
cut(fro,x,y);
link(z,x,y);
mp[p]=z;
}
return 0;
}