思路:
第一种是用带边权的方法来解
首先对于题目中的序列,我们用一个前缀和数组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
- #include
- #include
- #include
- 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<-1<
- return 0;
- }
- }else
- {
- f[pa]=pb;
- d[pa]=d[x]^d[y]^node[i].ans;
- }
- }
- cout<
-
-
- return 0;
- }
扩展域:
思路:
待写
代码:
- #include
- #include
- #include
- #include
- 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<-1<
- 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<-1<
- return 0;
- }
- f[get(x_odd)]=get(y_even);
- f[get(x_even)]=get(y_odd);
- }
- }
- cout<
- return 0;
- }
-
相关阅读:
2021年暨南大学计算机848真题
温度敏感/PH敏感/电场敏感/温度/pH双重敏感/磁场敏感型水凝胶的制备
VSCode学习笔记一:添加代码模板
P1008 [NOIP1998 普及组] 三连击
nonebot 原神角色查询插件
VSCode_快捷键
android 动画中插值器Interpolator详解
emqx broker安装
一段惊呆下巴的 JavaScript 代码
Springboot物资发放管理系统
-
原文地址:https://blog.csdn.net/m0_62327332/article/details/126859401