题意:浙江省第十二届大学生运动会在浙江师范大学举行,为此在浙师大建造了一座能容纳近万人的新体育场。
观众席每一行构成一个圆形,每个圆形由300个座位组成,对300个座位按照顺时针编号1到300,且可以认为有无数多行。现在比赛的组织者希望观众进入场地的顺序可以更加的有趣,在门票上并没有规定每个人的座位,而是与这个圈中某个人的相对位置,可以坐在任意一行。
门票上标示的形式如下:A B x 表示第B个人必须在A的顺时针方向x个位置(比如A坐在4号位子,x=2,则B必须坐在6号位子)。
现在你就座位志愿者在入场口检票。如果拿到一张门票,与之前给定的矛盾,则被视为是假票,如果无矛盾,视为真票。现在给定该行入场观众的顺序,以及他们手中的门票,请问其中有多少假票?
第一行两个数N(1<=N<=50,000)和m(1<=m<=100,000)。表示N个人,m张票。
思路:复习下带权并查集的模板
dis[x]代表路径压缩后到根结点的距离
合并集合时新的dis可以使用向量运算求出
1 var f,dis:array[1..60000]of longint; 2 n,m,i,u,v,x,y,z,ans:longint; 3 4 function find(k:longint):longint; 5 var x:longint; 6 begin 7 if k=f[k] then exit(k); 8 x:=f[k]; 9 f[k]:=find(f[k]); 10 dis[k]:=(dis[k]+dis[x]) mod 300; 11 exit(f[k]); 12 end; 13 14 procedure union(x,y,z:longint); 15 var u,v:longint; 16 begin 17 u:=find(x); v:=find(y); 18 f[v]:=u; 19 dis[v]:=(dis[x]+z-dis[y]+300) mod 300; 20 end; 21 22 begin 23 assign(input,'hdoj3047.in'); reset(input); 24 assign(output,'hdoj3047.out'); rewrite(output); 25 while not eof do 26 begin 27 readln(n,m); 28 if (n=0)and(m=0) then break; 29 ans:=0; 30 for i:=1 to n do 31 begin 32 f[i]:=i; dis[i]:=0; 33 end; 34 for i:=1 to m do 35 begin 36 readln(x,y,z); 37 u:=find(x); v:=find(y); 38 if u<>v then union(x,y,z) 39 else if (dis[x]+z) mod 300<>dis[y] then inc(ans); 40 end; 41 writeln(ans); 42 end; 43 close(input); 44 close(output); 45 end.
UPD(2018.10.18):C++
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second 19 #define MP make_pair 20 #define N 61000 21 #define M 6100000 22 #define eps 1e-8 23 #define pi acos(-1) 24 #define oo 1e9 25 26 int f[N],dis[N]; 27 28 int find(int k) 29 { 30 if(k==f[k]) return k; 31 int x=f[k]; 32 f[k]=find(f[k]); 33 dis[k]=(dis[k]+dis[x])%300; 34 return f[k]; 35 } 36 37 void Union(int x,int y,int z) 38 { 39 int u=find(x); 40 int v=find(y); 41 f[v]=u; 42 dis[v]=(dis[x]+z-dis[y]+300)%300; 43 } 44 45 int main() 46 { 47 //freopen("hdoj3047.in","r",stdin); 48 //freopen("hdoj3047.out","w",stdout); 49 int n,m; 50 while(scanf("%d%d",&n,&m)!=EOF) 51 { 52 int ans=0; 53 memset(dis,0,sizeof(dis)); 54 for(int i=1;i<=n;i++) f[i]=i; 55 for(int i=1;i<=m;i++) 56 { 57 int x,y,z; 58 scanf("%d%d%d",&x,&y,&z); 59 int u=find(x); 60 int v=find(y); 61 if(u!=v) Union(x,y,z); 62 else if((dis[x]+z)%300!=dis[y]) ans++; 63 } 64 printf("%d ",ans); 65 } 66 return 0; 67 }