题解 P5232 【[JSOI2012]智者的考验】

· · 题解

水题为什么没人做???

问题显然可以转化成带修地查询区间内前缀异或和为给定数的数量

根据题面来看,把所有按钮都取反跟原来是一样,也就是2^4=16种状态

区间修改为某个数的影响最多只有1次(两两抵消)

线段树上打打标记就可以了...

顺便献上我的blog:https://www.luogu.org/blog/Root-std-admin/

只给伪代码了嗷:

void build(int &p,int l,int r) {
    if (p==0) p=++num,t[p].l=t[p].r=t[p].sum=t[p].y=0,t[p].a=-1;
    t[p].c[N[0]]=((r-l)>>1)+(!(l&1)||!(r&1));
    t[p].c[N[o[0]]]=((r-l)>>1)+((l&1)||(r&1));
    t[p].sum=((((r-l)>>1)+((l&1)||(r&1)))&1)*o[0];
    if (l==r) return;
    int mid=l+r>>1;
    build(t[p].l,l,mid);
    build(t[p].r,mid+1,r);
}
void pd(int p,int l,int r) {
    if (t[p].a!=-1) {
        if (t[p].l) t[t[p].l].a=t[p].a,t[t[p].l].V=t[p].V,t[t[p].l].Q=t[p].Q,t[t[p].l].y=0;
        if (t[p].r) t[t[p].r].a=t[p].a,t[t[p].r].V=t[p].V,t[t[p].r].Q=t[p].Q,t[t[p].r].y=0;
        memset(t[p].c,0,sizeof(t[p].c));
        t[p].c[N[t[p].V]]=((r-l)>>1)+(!(l-t[p].Q&1)||!(r-t[p].Q&1));
        t[p].c[N[t[p].a^t[p].V]]=((r-l)>>1)+((l-t[p].Q&1)||(r-t[p].Q&1));
        t[p].sum=((((r-l)>>1)+((l-t[p].Q&1)||(r-t[p].Q&1)))&1)*t[p].a^((r-l+1&1)*t[p].V);
        t[p].a=-1;
    }
}
void up(int p,int l,int r) {
    int mid=l+r>>1;
    pd(t[p].l,l,mid);
    pd(t[p].r,mid+1,r);
    t[p].sum=t[t[p].l].sum^t[t[p].r].sum^(((mid-l+1)&1)*t[t[p].l].y)^(((r-mid)&1)*t[t[p].r].y);
    for (int i=0; i<16; i++) t[p].c[i]=t[t[p].l].c[N[s[i]^t[t[p].l].y]]+t[t[p].r].c[N[s[i]^t[t[p].r].y]];
}
void cg(int p,int l,int r,int po,int v) {
    if (po<=l) t[p].y^=v;
    else {
        pd(p,l,r);
        int mid=l+r>>1;
        cg(t[p].r,mid+1,r,po,v);
        if (mid>=po) cg(t[p].l,l,mid,po,v);
        up(p,l,r);
    }
}
int ask(int p,int l,int r,int po) {
    if (t[p].a!=-1) return (t[p].a*(po-t[p].Q&1))^t[p].V^t[p].y;
    if (l==r) return t[p].sum^t[p].y;
    int mid=l+r>>1;
    if (po<=mid) return ask(t[p].l,l,mid,po)^t[p].y;
    else return ask(t[p].r,mid+1,r,po)^t[p].y;
}
int que(int p,int l,int r,int L,int R,int v) {
    pd(p,l,r);
    v^=t[p].y;
    if (L==l&&R==r) return t[p].c[N[v]];
    int mid=l+r>>1;
    if (R<=mid) return que(t[p].l,l,mid,L,R,v);
    else if (L>mid) return que(t[p].r,mid+1,r,L,R,v);
    else
        return que(t[p].l,l,mid,L,mid,v)+que(t[p].r,mid+1,r,mid+1,R,v);
}
void ca(int p,int l,int r,int L,int R,int v,int V,int Q) {
    if (L==l&&R==r) {
        t[p].a=v;
        t[p].V=V;
        t[p].y=0;
        t[p].Q=Q;
        t[p].c[N[V]]=((r-l)>>1)+(!(l-Q&1)||!(r-Q&1));
        t[p].c[N[v^V]]=((r-l)>>1)+((l-Q&1)||(r-Q&1));
        t[p].sum=(((((r-l)>>1)+((l-Q&1)||(r-Q&1)))&1)*v)^((r-l+1&1)*V);
    } else {
        pd(p,l,r);
        V^=t[p].y;
        int mid=l+r>>1;
        if (R<=mid) ca(t[p].l,l,mid,L,R,v,V,Q);
        else if (L>mid) ca(t[p].r,mid+1,r,L,R,v,V,Q);
        else
            ca(t[p].l,l,mid,L,mid,v,V,Q),ca(t[p].r,mid+1,r,mid+1,R,v,V,Q);
        up(p,l,r);
    }
}
int main() {
    ios_base::sync_with_stdio(false);
    register int i,j;
    rx=read();
    ry=read();
    n=0;
    for (i=0; i<rx; i++)
        for (j=0; j<ry; j++) o[i]^=1<<(i*ry+j),o[j+rx]^=1<<(i*ry+j),q^=read()<<(i*ry+j);
    n=read();
    m=read();
    s[bo=num=0]=0;
    for(; bo<=num;) {
        for (i=0; i<rx+ry; i++) {
            for (j=0; j<=num; j++)
                if (s[j]==(s[bo]^o[i])) break;
            if (j>num) s[++num]=s[bo]^o[i];
            to[bo][i]=j;
        }
        bo++;
    }
    for (i=0; i<64; i++) N[i]=-1;
    for (i=0; i<=num; i++) N[s[i]]=i;
    num=0;
    build(ro,1,n);
    while (m--) {
        bo=read();
        if (bo==0) bo=read(),cg(ro,1,n,bo,o[read()-1]^ask(ro,1,n,bo)^(bo==1?0:ask(ro,1,n,bo-1)));
        else if (bo==1) if (bo=read(),x=read(),N[q]==-1) puts("0");
            else printf("%d\n",que(ro,1,n,bo,x,q));
        else if (rx=read(),ry=read(),x=o[read()-1],cg(ro,1,n,ry+1,ask(ro,1,n,ry)^(((ry-rx+1)&1)*x)),ca(ro,1,n,rx,ry,x,0,rx-1),rx-1) cg(ro,1,n,rx,ask(ro,1,n,rx-1));
    }
    return 0;
}

哦对,MN看数据范围,好像是1e6吧...

真心感谢大家观看,谢谢!!!