原题:node
huyichen和xuzhenyi在玩一个游戏:他写一个由0和1组成的序列。 huyichen选其中的一段(好比第3位到第5位),问他这段里面有奇数个1 仍是偶数个1。xuzhenyi回答你的问题,而后huyichen继续问。 xuzhenyi有可能在撒谎。huyichen要检查xuzhenyi的答案,指出在xuzhenyi的第几个回答必定有问题。 有问题的意思就是存在一个01序列知足这个回答前的全部回答,并且不存在序列 知足这个回答前的全部回答及这个回答。数组
第1行一个整数,是这个01序列的长度(≤1000000000)(≤1000000000) 第2行一个整数,是问题和答案的个数(≤5000)(≤5000)。 第3行开始是问题和答案, 每行先有两个整数,表示你询问的段的开始位置和结束位置。 而后是xuzhenyi的回答。odd表示有奇数个1,even表示有偶数个ui
输出一行,一个数X,表示存在一个01序列知足第1到第X个回答, 可是不存在序列知足第1到第X+1个回答。若是全部回答都没问题,你就输出 全部回答的个数。atom
很明显,这道题是并查集(不要问我怎么看出来的)。spa
因为数据太大,须要离散化。.net
所谓离散化,就是把较大的一组数进行排序,而后对他们根据大小从新赋值,当数的大小不对数据自己有影响,只有大小对其有影响时,可使用离散化。code
离散化的标准姿式见 点这里xml
然而蒟蒻并不会标准姿式,说说本身的方法:blog
以本题为例,把全部的数据都存在nd结构体中排序
void init() { for(int i = 1;i<=m;i++) { int x,y; scanf("%d%d%s",&x,&y,c); nd[i].p = x;//数组开三倍,p表示临时变量。一倍存左端点。 nd[i+m].p = y;//二倍存右端点。 nd[i].num = i;//每一倍都要给他们打上编号,一会排序时后会乱。 nd[i+m].num = i;if(c[0]=='e') { nd[i+m+m].odd = 0;//三倍存奇偶 }else { nd[i+m+m].odd = 1; } } }
读进来以后进行离散化。
void discretization() { for(int i = 1;i<=2*m;i++) { if(nd[nd[i].num].l==-1) { nd[nd[i].num].l = cnt-1; }else { nd[nd[i].num].r = cnt; } if(nd[i+1].p!=nd[i].p) { cnt++; //去重,不同的时候再+1 } } for(int i = 1;i<=m;i++) { nd[i].odd = nd[i+m+m].odd;从三倍搬回原数组 } }
这样就离散完了。
接下来就是带权并查集的操做。
在合并和路径压缩的时候处理。
思路就是将一个区间右面的点认左面的点为父亲,两端区间合并的时候,根据奇偶性判断,0表示偶数,1表示奇数(有点懒,具体0或1见代码)。
int find(int x) { if(f[x]==x) { return f[x]; } int fx = find(f[x]); g[x] = (g[f[x]]+g[x])%2; return f[x] = fx; }
最后上总代码:
#include<cstdio> #include<algorithm> #include<cmath>
#define ll long long
#define N 105550
using namespace std; char c[20]; ll n; int m; int cnt = 1; struct node { int l; int r; int num; int odd; int p; }nd[N+N+N]; int f[N]; int g[N]; int cmp(node a,node b) { return a.p < b.p; } void init() { for(int i = 1;i<=m;i++) { int x,y; scanf("%d%d%s",&x,&y,c); nd[i].p = x; nd[i+m].p = y; nd[i].num = i; nd[i+m].num = i; nd[i].l = -1; nd[i+m].l = -1; if(c[0]=='e') { nd[i+m+m].odd = 0; }else { nd[i+m+m].odd = 1; } } } void discretization() { for(int i = 1;i<=2*m;i++) { if(nd[nd[i].num].l==-1) { nd[nd[i].num].l = cnt-1; }else { nd[nd[i].num].r = cnt; } if(nd[i+1].p!=nd[i].p) { cnt++; } } for(int i = 1;i<=m;i++) { nd[i].odd = nd[i+m+m].odd; } } int find(int x) { if(f[x]==x) { return f[x]; } int fx = find(f[x]); g[x] = (g[f[x]]+g[x])%2; return f[x] = fx; } int ans; bool flag; void uion(int x,int y,int i) { int fx = find(x); int fy = find(y); if(fx==fy) { if((nd[i].odd==1&&g[x]==g[y])||(nd[i].odd==0&&g[x]!=g[y])) { ans = i-1; flag = 1; return ; } find(y); find(x); }else { f[fy] = fx; g[fy] = (g[x]+g[y]+nd[i].odd)%2; find(x); find(y); } } void solve() { for(int i = 1;i<=cnt;i++) { f[i] = i; } for(int i = 1;i<=m;i++) { int l = nd[i].l; int r = nd[i].r; uion(l,r,i); if(flag==1) { printf("%d\n",ans); return ; } } printf("%d\n",m); } int main() { scanf("%lld",&n); scanf("%d",&m); init(); sort(nd+1,nd+1+m+m,cmp); discretization(); solve(); return 0; }