<题目链接>
题目大意:
一个由0,1组成的序列,每次给出一段区间的奇偶,问哪一条信息不合法。
解题分析:
我们用s[i]表示前i个数的前缀和,那么a b even意味着s[b]和s[a-1]的奇偶性相同。a b odd意味着s[b]与s[a-1]的奇偶性不同。于是我们根据奇偶性的不同,用并查集依次处理他们之间的关系。当某条信息出现与并查集中记录的信息不符合时,则此信息不合法。
由于该序列的长度达到了1e9,并且查询次数只有5000次,所以我们需要对查询的区间进行离散化,否则存不下,数据比较小,用map离散化即可,也不会很慢。
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <map> using namespace std; #define RP(i,s,t) for(int i=s;i<=t;i++) #define fastIO ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); const int N = 1e4 + 5; int n, m, tot,fa[N + 10], w[N + 10]; map<int,int>mp; int find(int x){ if(x==fa[x])return x; int tmp=fa[x]; fa[x]=find(fa[x]); w[x]=(w[x]+w[tmp]+2)%2; //带权并查集关系的转移 return fa[x]; } inline bool Union(int a,int b,int x){ int ra=find(a),rb=find(b); if(ra!=rb){ fa[ra]=rb; w[ra]=(w[a]-w[b]+x+2)%2; }else{ if((w[a]-w[b]+2)%2!=x)return false; //与之前建立的关系奇偶性不符,则表示出现冲突 }return true; } int main() { fastIO cin >> n >> m; RP(i, 1, N + 5) fa[i] = i, w[i] = 0; int ans=0; RP(i,1,m){ int a,b;string s; cin>>a>>b>>s;--a; //因为根据的是前缀和的奇偶性,所以这里a要记得-1 if(!mp[a])mp[a]=++tot; //map用来离散化 if(!mp[b])mp[b]=++tot; int k=(s=="odd")?1:0; //odd才是奇,容易搞错 if(Union(mp[a],mp[b],k))ans++; else break; }cout<<ans<<' '; }
2018-10-02