蓝书(算法竞赛进阶指南)刷题记录——POJ1733 Parity game(带权并查集)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/88917302

题目:POJ1733.
题目大意:给定 n n 个区间 [ l i , r i ] [l_i,r_i] a i a_i ,表示 [ l i , r i ] [l_i,r_i] 的权值和为奇数或偶数,问到哪一个区间不矛盾,但它的下一个区间矛盾.
1 n 5 1 0 3 1\leq n\leq 5*10^3 .

容易想到前缀和,那么区间就变成了两个点 l i 1 l_i-1 r i r_i 上的信息.

考虑用带权并查集维护每个点的前缀和 d [ i ] d[i] ,一个点 i i 的点权表示 i i 的前缀和异或 i i 的父亲的点权,即区间 [ f a [ i ] + 1 , i ] [fa[i]+1,i] 的奇偶性.

加入一个区间 [ l i , r i ] [l_i,r_i] 时若 l i 1 , r i l_i-1,r_i 在同一个区间就大力判断它们点权异或是否等于 a [ i ] a[i] .然后加入这个区间就相当于把 r i r_i 的祖先设为 l i 1 l_i-1 ,并同时更新点权.

注意这个时候路径压缩时也要更新点权.

时间复杂度 O ( n log n ) O(n\log n) .

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=5000;

int ri(){
  char c=getchar();
  int x=0,y=1;
  for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x*y;
}

int rc(){
  char c=getchar();
  while (c<'a'||c>'z') c=getchar();
  return c=='o'?1:0;
}

int n,ord[N*2+9],x[N+9],y[N+9],a[N+9];
int fa[N*2+9],d[N*2+9],ans;

int lower(int k){
  int l=1,r=n<<1,mid=l+r>>1;
  for (;l<r;mid=l+r>>1)
    k<=ord[mid]?r=mid:l=mid+1;
  return l;
}

int get(int u){
  if (u==fa[u]) return u;
  int rot=get(fa[u]);d[u]^=d[fa[u]];
  return fa[u]=rot;
}

Abigail into(){
  ri();n=ri();
  for (int i=1;i<=n;++i){
  	x[i]=ri()-1;y[i]=ri();a[i]=rc();
  	ord[i*2-1]=x[i];ord[i*2]=y[i];
  }
}

Abigail work(){
  sort(ord+1,ord+1+2*n);
  for (int i=0;i<=n;++i)
    x[i]=lower(x[i]),y[i]=lower(y[i]);
  for (int i=1;i<=n<<1;++i) fa[i]=i;
  int u,v;
  ans=n;
  for (int i=1;i<=n;++i){
  	u=get(x[i]);v=get(y[i]);
  	if (u==v&&d[x[i]]^d[y[i]]^a[i]){ans=i-1;return;}
  	fa[v]=u,d[v]=d[x[i]]^d[y[i]]^a[i];
  }
}

Abigail outo(){
  printf("%d\n",ans);
}

int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/88917302
今日推荐