zoukankan      html  css  js  c++  java
  • 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;
    }  
    

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

  • 相关阅读:
    oracle实例的内存(SGA和PGA)调整,优化数据库性能
    Redhat 安装perl模块
    三、Java基础---------关于继承、构造函数、静态代码块执行顺序示例讲解
    二、Java基础--02
    一、Java基础--01
    提醒用户收到短信
    手机屏幕更改
    查看手机信息和SIM卡信息
    还原和设置手机桌面背景
    wifi的开与关
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12527483.html
Copyright © 2011-2022 走看看