题目3 : 八卦的小冰
描述
小冰是个八卦的人,最近她对一个社交网站很感兴趣。
由于小冰是个机器人,所以当然可以很快地弄清楚这个社交网站中用户的信息啦。
她发现这个社交网站中有N个用户,用户和用户之间可以进行互动。小冰根据用户之间互动的次数和内容判断每对用户之间的亲密度。亲密度非负,若大于零表示这两个用户之间是好友关系。由于这个网站是活跃的,所以小冰会不停地更新用户之间的亲密度。
由于隐私保护,小冰无法知道每个用户的确切性别,但是作为一只很聪明的人工智能,小冰可以通过每个用户的行为来猜测性别。当然这种猜测是不准确的,小冰有可能会改变对一个用户的判断。
小冰想知道这个社交网络的八卦度是多少。八卦度的定义是社交网络中所有异性好友之间的亲密度之和。你能帮助她吗?
输入
第一行一个整数T,表示数据组数。接下来是T组数据,每组数据的格式如下:
第一行是三个整数N, M, Q,分别表示用户数、初始的好友对数、操作数。
第二行是N个空格隔开的数,第i个数表示i号用户的性别,用0或1表示。
接下来的M行,每行三个数x, y, z,代表初始状态用户x和用户y之间的亲密度是z。除此之外的用户之间的亲密度初始为0。
接下来是Q行,每行是以下三种操作中的一种:
1. “1 x”:改变用户x的性别
2. “2 x y z”:改变用户x与用户y之间的亲密度为z
3. “3”:询问八卦度
输出
对于每组数据首先输出一行"Case #X:",X为测试数据编号。
接下来对于每一个询问,输出一行包含询问的八卦度。
数据范围
1 ≤ T ≤ 20
1 ≤ x, y ≤ N
0 ≤ z ≤ 100000
小数据
1 ≤ N, M ≤ 100
1 ≤ Q ≤ 1000
大数据
1 ≤ N, M, Q ≤ 100000
-
样例输入
-
1 3 2 8 0 1 0 1 2 1 1 3 1 3 1 1 1 2 3 2 2 3 2 3 1 2 3
样例输出
-
Case #1: 1 2 2 3
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /*记录无向图的边数*/ 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #define MAX 100010 6 using namespace std; 7 int SEX[100010]; //性别 8 typedef struct edge 9 { 10 int TO; //下一个顶点 11 int Next; //记录下一条边的编号 12 int Vlaue; //权值 13 }EDGE; 14 EDGE ID[3*MAX]; //边表,坑爹的边数,记得弄多点,不然有时候也会提示超时。 15 int First[MAX]; //First[x]:x表示头结点为x,First[x]表示下一条边的编号 16 int SIGN; 17 long long sum; 18 void Add_E(int x,int y,int z) //添加边 19 { 20 ID[SIGN].TO=y; 21 ID[SIGN].Vlaue=z; 22 ID[SIGN].Next=First[x]; 23 First[x]=SIGN++; 24 } 25 26 void C_SEX() 27 { 28 int n,i; 29 scanf("%d",&n); 30 SEX[n]=1-SEX[n]; //改变性别 31 for(i=First[n];i!=0;i=ID[i].Next) //查找与该点相关的点 32 { 33 if(SEX[ID[i].TO]==SEX[n]) //与修改后的性别一样, 34 { //说明之前是加上该点的权值, 35 sum-=ID[i].Vlaue; //减去该点的权值 36 } 37 else 38 { //与修改后的性别不一样 39 sum+=ID[i].Vlaue; //说明之前是没有加上该点的权值, 40 } //现在就加上该点的权值 41 } 42 return ; 43 } 44 void C_Map() 45 { 46 int x, y, z,i,Begin=0; 47 scanf("%d %d %d",&x,&y,&z); 48 for(i=First[x];i!=0;i=ID[i].Next)//查找是否已经存在的关系 49 { 50 if(ID[i].TO==y)//存在关系 51 { 52 Begin=ID[i].Vlaue; 53 ID[i].Vlaue=z; 54 break; 55 } 56 } 57 if(i!=0) 58 { 59 for(i=First[y];i!=0;i=ID[i].Next)//查找是否已经存在的关系 60 { 61 if(ID[i].TO==x)//存在关系 62 { 63 ID[i].Vlaue=z; 64 break; 65 } 66 } 67 } 68 else if(i==0)//如果没有存在关系,创建两个点 69 { 70 Add_E(x,y,z); 71 Add_E(y,x,z); 72 } 73 if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值 74 sum+=(z-Begin); 75 76 return ; 77 } 78 79 void FIND()//输出答案 80 { 81 printf("%lld\n",sum); 82 return ; 83 } 84 void work() 85 { 86 int N; 87 scanf("%d",&N); 88 switch(N) 89 { 90 case 1:C_SEX();break; 91 case 2:C_Map();break; 92 case 3:FIND();break; 93 } 94 return ; 95 } 96 int main() 97 { 98 int T,i,t; 99 int N,M,Q; 100 int x,y,z; 101 scanf("%d",&T); 102 t=1; 103 while(T--) 104 { 105 scanf("%d %d %d",&N,&M,&Q); 106 SIGN=1;sum=0; 107 for(i=1;i<=N;i++) 108 { 109 scanf("%d",&SEX[i]); 110 First[i]=0; 111 } 112 for(i=1;i<=M;i++) 113 { 114 scanf("%d %d %d",&x,&y,&z); 115 Add_E(x,y,z); 116 Add_E(y,x,z); 117 if(SEX[x]!=SEX[y])sum+=z; //判断性别不一样相加 118 } 119 printf("Case #%d:\n",t++); 120 while(Q--) 121 { 122 work(); 123 } 124 } 125 return 0; 126 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /*按照链表的边数记录*/ 2 #include <iostream> 3 #include <stdio.h> 4 #include <string.h> 5 #define MAX 100010 6 using namespace std; 7 int Len; //人数 8 int SEX[100010]; //性别 9 typedef struct edge 10 { 11 int TO; //下一个顶点 12 int Next; //记录下一条边的编号 13 int Vlaue; //权值 14 }EDGE; 15 EDGE ID[3*MAX]; //边表,坑爹的边数记得多弄些,不然有可能会TLE 16 int First[MAX]; //First[x]:x表示头结点为x,First[x]表示下一条边的编号 17 int SIGN; 18 long long sum; 19 void Add_E(int x,int y,int z) //添加边 20 { 21 if(SEX[x]!=SEX[y])sum+=z; //判断性别不一样相加 22 ID[SIGN].TO=y; 23 ID[SIGN].Vlaue=z; 24 ID[SIGN].Next=First[x]; 25 First[x]=SIGN++; 26 } 27 28 void C_SEX() 29 { 30 int n,i; 31 scanf("%d",&n); 32 SEX[n]=1-SEX[n]; //改变性别 33 for(i=First[n];i!=0;i=ID[i].Next) //查找与该点相关的点 34 { 35 if(SEX[ID[i].TO]==SEX[n]) //与修改后的性别一样, 36 { //说明之前是加上该点的权值, 37 sum-=ID[i].Vlaue*2; //减去该点的权值(无向图) 38 } 39 else 40 { //与修改后的性别不一样 41 sum+=ID[i].Vlaue*2; //说明之前是没有加上该点的权值, 42 } //现在就加上该点的权值(无向图) 43 44 } 45 } 46 void C_Map() 47 { 48 int x, y, z,i; 49 scanf("%d %d %d",&x,&y,&z); 50 for(i=First[x];i!=0;i=ID[i].Next)//查找是否已经存在的关系 51 { 52 if(ID[i].TO==y)//存在关系 53 { 54 if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值 55 sum+=(z-ID[i].Vlaue); 56 ID[i].Vlaue=z; 57 break; 58 } 59 } 60 if(i!=0) 61 { 62 for(i=First[y];i!=0;i=ID[i].Next)//查找是否已经存在的关系 63 { 64 if(ID[i].TO==x)//存在关系 65 { 66 if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值 67 sum+=(z-ID[i].Vlaue); 68 ID[i].Vlaue=z; 69 break; 70 } 71 } 72 } 73 else if(i==0)//如果没有存在关系,创建两个点 74 { 75 Add_E(x,y,z); 76 Add_E(y,x,z); 77 } 78 79 } 80 81 void FIND()//输出答案 82 { 83 printf("%lld\n",sum/2);//无向图,所以/2; 84 } 85 void work() 86 { 87 int N; 88 scanf("%d",&N); 89 switch(N) 90 { 91 case 1:C_SEX();break; 92 case 2:C_Map();break; 93 case 3:FIND();break; 94 } 95 } 96 int main() 97 { 98 int T,i,t; 99 int N,M,Q; 100 int x,y,z; 101 scanf("%d",&T); 102 t=1; 103 while(T--) 104 { 105 scanf("%d %d %d",&N,&M,&Q); 106 Len=N;SIGN=1;sum=0; 107 for(i=1;i<=N;i++) 108 { 109 scanf("%d",&SEX[i]); 110 First[i]=0; 111 } 112 for(i=1;i<=M;i++) 113 { 114 scanf("%d %d %d",&x,&y,&z); 115 Add_E(x,y,z); 116 Add_E(y,x,z); 117 } 118 printf("Case #%d:\n",t++); 119 for(i=0;i<Q;i++) 120 { 121 work(); 122 } 123 } 124 return 0; 125 }