bzoj 3651: 网络通信

3651: 网络通信

Time Limit: 10 Sec   Memory Limit: 256 MB
Submit: 83   Solved: 58
[ Submit][ Status][ Discuss]

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.

HINT

Source


题解:这道题是学长出的互测题的第二题,被学长贴标签为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;  }
  } 
}




你可能感兴趣的:(bzoj 3651: 网络通信)