思路:
第一种是用带边权的方法来解
首先对于题目中的序列,我们用一个前缀和数组sum[i]来表示1~i中所有数的奇数的个数。
可以发现假如题目给的一个范围[l,r]里面有偶数个1,等价于sum[l-1]与sum[r]的奇偶性相同,
证明:s[l,r]里面的奇偶性可以由sum[r]-sum[l-1]得到,s[l,r]有偶数个1,说明sum[r]-sum[l-1]要么是两个偶数,要么是两个奇数。否则得不出s[l,r]里面是有偶数个1这个结论。
[l,r]里面有奇数个1的情况下说明,sum[l-1]与sum[r]的奇偶性不同。证明和上面类似,此处略。
这道题目里面要传递的关系不止一种,
1.x1与x2的奇偶性相同+x2与x3的奇偶性相同可以得到x1和x3的奇偶性相同
2.x1与x2的奇偶性相同+x2与x3的奇偶性不同可以得到x1和x3的奇偶性不同
3.x1与x2的奇偶性不同+x2与x3的奇偶性不同可以得到x1和x3的奇偶性相同
步骤
0.首先注意到题目s的序列长度很大,但回答的次数却很小,所以这里要先离散化一下,
1.用一个并查集树来表示一个集合,d[i]表示当前节点跟f[x]节点的奇偶性关系,0表示相同,1表示不同。在路径压缩的同时对x到根节点路径上的所有边权做异或运算便可得到x和根节点的关系。
同时,如果想获得同一棵树里面的两个不同节点的奇偶性关系就是直接d[x]^d[y],这里就使用到了上面所说的关系传递。
2.对于每一个回答,都要先判断x,y是否属于同一集合,如果是的话就用d[x]^d[y]去对比回答里面的关系是否相同。
如果x,y不属于同一集合,就要合并两个集合,得到两个集合的根节点pa,pb后,令pa为pb的子节 点。有ans=d[x]^d[y]^d[pa]可以得到d[pa]=ans^d[x]^d[y];
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=3e4+10;
struct nod
{
int l,r, ans;
}node[N];
int a[N],f[N],d[N];
int n,m,t;
void getdata()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
char str[5];
scanf("%d%d%s",&node[i].l,&node[i].r,str);
if(str[0]=='o') node[i].ans=1;
else node[i].ans=0;
a[++t]=node[i].l-1;
a[++t]=node[i].r;
}
sort(a+1,a+t+1);
n=unique(a+1,a+t+1)-a-1;
}
int get(int x)
{
if(x==f[x]) return x;
int u=get(f[x]);
d[x]^=d[f[x]];
return f[x]=u;
}
int main()
{
getdata();
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++)
{
int x=lower_bound(a+1,a+n+1,node[i].l-1) -a;
int y=lower_bound(a+1,a+n+1,node[i].r) -a;
int pa=get(x),pb=get(y);
if(pa==pb)
{
if((d[x]^d[y])!=node[i].ans)
{
cout<<i-1<<endl;
return 0;
}
}else
{
f[pa]=pb;
d[pa]=d[x]^d[y]^node[i].ans;
}
}
cout<<m<<endl;
return 0;
}
扩展域:
思路:
待写
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=3e4+10;
struct nod
{
int l,r, ans;
}node[N];
int a[N],f[N],d[N];
int n,m,t;
void getdata()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
char str[5];
scanf("%d%d%s",&node[i].l,&node[i].r,str);
if(str[0]=='o') node[i].ans=1;
else node[i].ans=0;
a[++t]=node[i].l-1;
a[++t]=node[i].r;
}
sort(a+1,a+t+1);
n=unique(a+1,a+t+1)-a-1;
}
int get(int x)
{
if(x==f[x])
return x;
return f[x]=get(f[x]);
}
int main()
{
getdata();
for(int i=1;i<=2*n;i++)
f[i]=i;
for(int i=1;i<=m;i++)
{
int x= lower_bound(a+1,a+n+1,node[i].l-1) -a;
int y=lower_bound(a+1,a+n+1,node[i].r) -a;
int x_odd=x,x_even=x+n;
int y_odd=y,y_even=y+n;
if(node[i].ans==0)
{
if(get(x_odd)==get(y_even))
{
cout<<i-1<<endl;
return 0;
}
f[get(x_odd)]=get(y_odd);
f[get(x_even)]=get(y_even);
}else
{
if(get(x_odd)==get(y_odd))
{
cout<<i-1<<endl;
return 0;
}
f[get(x_odd)]=get(y_even);
f[get(x_even)]=get(y_odd);
}
}
cout<<m<<endl;
return 0;
}