P5522 [yLOI2019] 棠梨煎雪

updata on 2020.3.19
今天把博客从洛谷往博客园搬,图炸了
其实早就发现了,懒得管
那图其实就是一个用dev自带的调试功能调试时,RE了的报错
当时觉得很奇怪看不出是啥,现在再看已经觉得不稀罕了RE越来越多?
所以图就不再放了

P5522 [yLOI2019] 棠梨煎雪

整理博客的时候改了一下分类标签,重新审一下

线段树+每次pushup暴力比较

先说说我在比赛中打这道题的虐心经历吧。。。:
先是指针线段树的root在地址数组里占了第一位,
但tot却初始化为0.....
这就导致了单步调试时出现了让蒟蒻不知所措的奇怪报错:
就是这,图炸了

解决后,却发现询问中n和m居然用混了......
导致比赛中这题只得了5分
所以,以我的经历提醒大家:注意变量名!注意变量名!注意变量名!可能也只有我会把变量搞混吧。。。
----------------------------------------------手动正文分割线-----------------------------------------------

思路:

区间查询,单点修改,所以,你想到了什么?

没错,就是线段树!

我们用一个res结构体存ans和x数组:
ans表示当前l~r有几种可能的情况,如果为0就是发生了冲突,x表示可以确定的(当然我是用3表示“?”)
很显然,因为每个"?"都可以填0或1,所以对于又n个?的数列,他的可能情况数量就是 (2^n)

struct res{
	LL ans;
	int x[35] 
};  

再想想怎么build?
每次当lr(也就是到了叶节点),就扫一遍对应的数组,将其转存到对应的x里,如果出现3(也就是“?”),就(ans imes 2),当然ans要初始化为1(各位大佬应该不用我提醒。。。
当然修改和这个也差不多
那怎么将两个儿子信息合并到父节点?
我用了一个以res为返回类型的cmp函数:
如果左右有任意一个儿子ans
0(有冲突),那么父节点的ans直接为0
然后逐一暴力比对,对于每两个对应的原素:

  1. 相等且不等于3:ret.x[i]=aa.x[i],ans不变
  2. 相等且等于3:ret.x[i]=3,(ans imes 2)
  3. 不等且都不为3:说明发生了冲突,ans=0,返回
  4. 不等且一个为3:ret.x[i]赋值为不等于3的那个,ans不变

下面是这个函数的代码:(上面讲的应该比较清晰了,就不再注释了)

inline res cmp(res aa,res bb){
	res ret;
	if(aa.ans==0||bb.ans==0){
		ret.ans=0;
		return ret;
	}
	ret.ans=1;
	for(R int i=1;i<=n;i++){
		if(aa.x[i]==bb.x[i]){
			if(aa.x[i]!=3){
				ret.x[i]=aa.x[i];
				continue;
			}
			else{
				ret.x[i]=3;
				ret.ans*=2;
			}
		}
		if(aa.x[i]!=3&&bb.x[i]!=3){
			ret.ans=0;
			return ret;
		}
		if(aa.x[i]==3)
			ret.x[i]=bb.x[i];
		else ret.x[i]=aa.x[i];
	}
	return ret;
}

然后再把这给函数返回的ret赋值给当前节点就行了
tree->o=cmp(tree->ls->o,tree->rs->o);
最后一个问题,怎么查询?
我们还是要用到cmp函数,比较从两个子节点返回的信息,然后返回到上层
好了,应该就这些了吧,放上代码(我知道这才是泥萌想要的

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define R register
#define EN printf("
")
#define LL long long
inline int read(){
	int x=0,y=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
	return x*y;
}
int n,m,q;
struct res{
	LL ans;
	int x[35];
};
struct tr{
	tr *ls,*rs;
	res o;
}dizhi[200017],*root=&dizhi[0];
int tot;
int now[35],a[100017][35];
inline res cmp(res aa,res bb){
	res ret;
	if(aa.ans==0||bb.ans==0){
		ret.ans=0;
		return ret;
	}
	ret.ans=1;
	for(R int i=1;i<=n;i++){
		if(aa.x[i]==bb.x[i]){
			if(aa.x[i]!=3){
				ret.x[i]=aa.x[i];
				continue;
			}
			else{
				ret.x[i]=3;
				ret.ans*=2;
			}
		}
		if(aa.x[i]!=3&&bb.x[i]!=3){
			ret.ans=0;
			return ret;
		}
		if(aa.x[i]==3)
			ret.x[i]=bb.x[i];
		else ret.x[i]=aa.x[i];
	}
	return ret;
}
void build(tr *tree,int l,int r){
	if(l==r){
		tree->o.ans=1;
		for(R int i=1;i<=n;i++){
			tree->o.x[i]=a[l][i];
			if(a[l][i]==3) tree->o.ans*=2;
		}
		return;
	}
	int mid=(l+r)>>1;
	tree->ls=&dizhi[++tot];
	tree->rs=&dizhi[++tot];
	build(tree->ls,l,mid);
	build(tree->rs,mid+1,r);
	tree->o=cmp(tree->ls->o,tree->rs->o);
}
void change(tr *tree,int l,int r,int k){
	if(l==r){
		tree->o.ans=1;
		for(R int i=1;i<=n;i++){
			tree->o.x[i]=now[i];
			tree->o.ans*=2;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(k<=mid) change(tree->ls,l,mid,k);
	else change(tree->rs,mid+1,r,k);
	tree->o=cmp(tree->ls->o,tree->rs->o);
}
res qq(tr *tree,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr) {
		return tree->o;
	}
	int mid=(l+r)>>1;
	res aa,bb;
	aa.ans=bb.ans=-1;
	if(ql<=mid) aa=qq(tree->ls,l,mid,ql,qr);
	if(qr>mid) bb=qq(tree->rs,mid+1,r,ql,qr);
	if(aa.ans==-1) return bb;
	if(bb.ans==-1) return aa;
	return cmp(aa,bb);
}
int main(){
	char c;
	int anss=0;
	n=read();m=read();q=read();
	for(R int i=1;i<=m;i++){
		c=getchar();
		while(c==' '||c=='
') c=getchar();
		for(R int j=1;j<=n;j++){
			if(c=='?') a[i][j]=3;
			else a[i][j]=c-48;
			c=getchar();
		}
	}
	build(root,1,m);
	for(R int i=1;i<=q;i++){
		int op=read();
		if(op){
			op=read();
			c=getchar();
			while(c==' ') c=getchar();
			for(R int j=1;j<=n;j++){
				if(c=='?') now[j]=3;
				else now[j]=c-48;
				c=getchar();
			}
			change(root,1,m,op);
		}
		else{
			int l=read(),r=read();
			anss^=qq(root,1,m,l,r).ans;
		}
	}
	printf("%d",anss^0);
	return 0;
}  

这是身为蒟蒻的我写的第一篇题解,有错误或没讲明白的地方, 欢迎各位大佬私信

原文地址:https://www.cnblogs.com/suxxsfe/p/12527483.html