P5522 [yLOI2019] 棠梨煎雪 - 线段树

Posted on 2020-10-13 21:37  Choimoe  阅读(23)  评论(0编辑  收藏  举报

P5522 [yLOI2019] 棠梨煎雪

题目背景

岁岁花藻檐下共将棠梨煎雪,

自总角至你我某日辗转天边。

天淡天青,宿雨沾襟,

一年一会信笺却只见寥寥数言。

——银临《棠梨煎雪》

题目描述

歌词中的主人公与她的朋友一年会有一次互相写信给对方,一共通信了 m 年。为了简化问题,我们认为她们每封信的内容都是一条二进制码,并且所有二进制码的长度都是 n。即每封信的内容都是一个长度为 n 的字符串,这个字符串只含字符 01

这天她拿出了朋友写给她的所有信件,其中第 i 年的写的信件编号为 i。由于信件保存时间过久,上面有一些字符已经模糊不清,我们将这样的位置记为 ?? 字符可以被解释为 01。由于她的朋友也是人,符合人类的本质,所以朋友在一段连续的时间中书写的内容可能是相同的。现在她想问问你,对于一段连续的年份区间 [l,r] 中的所有信件,假如朋友在这段时间展示了人类的本质,所写的是同一句话,那么这一句话一共有多少种可能的组成。也即一共有多少字符串 S,满足在这个区间内的所有信件的内容都可能是 S

一个长度为 n 的只含 0,1,? 的字符串 A 可能是一个字符串 B 当且仅当 B 满足如下条件:

  • B 的长度也是 n
  • B 中只含字符 0,1
  • A 中所有为 0 的位置在 B 中也是 0
  • A 中所有为 1 的位置在 B 中也是 1
  • A 中为 ? 的位置在 B 中可以为 0 也可以是 1

同时她可能会突然发现看错了某年的信的内容,于是她可能会把某一年的信的内容修改为一个别的只含 0,1,? 的长度为 n 的字符串。

输入格式

每个输入文件中都有且仅有一组测试数据。

输入数据第一行为三个用空格隔开的整数,分别代表代表字符串长度 n,字符串个数 m 和操作次数 q

下面 m 行,每行是一个长度为 n 的字符串,第 (i+1) 行的字符串 s**i 代表第 i 年信的内容。

下面 q 行,每行的第一个数字是操作编号 opt

  • 如果 opt=0,那么后面接两个整数 [l, r],代表一次查询操作。
  • 如果 opt=1,那么后面接一个整数 pos,在一个空格后会有一个长度为 n 的字符串 t,代表将第 pos 个字符串修改为新的字符串 t

输出格式

为了避免输出过大,请你输出一行一个数代表所有查询的答案异或和对 0 取异或的结果。

题解

注意到每一位是独立的之后就不难想到对于每一位建个线段树,复杂度 \(\text O(nq\log m)\) 得到了70分的好成绩

其实发现可以将 0 赋成 011 赋成 10? 赋成 11,就可以得到下面运算:

  • 0 & 0 = 01 & 1 = 1
  • ? & 0 = 0? & 1 = 1
  • ? & ? = ?

于是就可以把30颗线段树压成一个 ull ,就可以顺利压到 \(\text O(q\log m)\)

#include<bits/stdc++.h>

#define int unsigned long long
#define jk(i,j,k) for(int i=(j);i<=(k);i++)
#define kj(i,j,k) for(int i=(j);i>=(k);i--)

int rd(){int data=0,w=1;char ch=0;while(ch!='-'&&(ch>'9'||ch<'0'))ch=getchar();(ch=='-')&&(w=-1,ch=getchar());while(ch>='0'&&ch<='9'){data=data*10+ch-'0';ch=getchar();}return data*w;}
void P(int v){if(v<0){putchar('-');v=-v;}if(v>9)P(v/10);putchar(v%10+'0');}

#define N 40
#define M 100010
#define lc o<<1
#define rc o<<1|1

int fl[N*N],n,q,o,l,r,R,B[N],E,m,g[M];
char s[N];

struct No{int l,r;int s;}t[M<<2];

int Bi(int X){int r=1;jk(i,1,n)r*=B[X%4],X>>=2;return r;}
void upd(int o){t[o].s=t[lc].s&t[rc].s;}
void bui(int o,int l,int r){
	t[o].l=l;t[o].r=r;
	if(l==r){t[o].s=g[l];return;}
	int mi=(l+r)>>1;
	bui(lc,l,mi);bui(rc,mi+1,r);upd(o);
}
void cha(int o,int x,int d){
	if(x<t[o].l||x>t[o].r)return;
	if(t[o].l==t[o].r){t[o].s=d;return;}
	cha(lc,x,d);cha(rc,x,d);upd(o);
}
int que(int o,int l,int r){
	if(r<t[o].l||l>t[o].r)return (1ull<<63)-1ull;
	if(l<=t[o].l&&r>=t[o].r)return t[o].s;
	return que(lc,l,r)&que(rc,l,r);
}

signed main(){
	B[fl['0']=1]=1;B[fl['1']=2]=1;B[fl['?']=3]=2;
	n=rd();m=rd();q=rd();
	jk(i,1,m){scanf("%s",s+1);jk(j,1,n)g[i]=g[i]<<2|fl[s[j]];}
	bui(1,1,m);
	jk(Q,1,q){
		o=rd();l=rd();
		if(o){scanf("%s",s+1);jk(i,1,n)m=m<<2|fl[s[i]];cha(1,l,m);}
		else E^=Bi(que(1,l,rd()));
	}
	P(E);
}