又是nand

Description
首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5。给出一棵树,树上每个点都有点权,定义树上从a到b的费用为0与路径上的点的权值顺次nand的结果,例如:从2号点到5号点顺次经过2->3->5,权值分别为5、7、2,K=3,那么最终结果为0 nand 5 nand 7 nand 2=7 nand 7 nand 2=0 nand 2=7,现在这棵树需要支持以下操作。
① Replace a b:将点a(1≤a≤N)的权值改为b。
② Query a b:输出点a到点b的费用。
请众神给出一个程序支持这些操作。

Input
第一行N,M,K,树的节点数量、总操作个数和运算位数。
接下来一行N个数字,依次表示节点i的权值。
接下来N-1行,每行两个数字a,b(1≤a,b≤N)表示a,b间有一条树边。
接下来M行,每行一个操作,为以上2类操作之一。
N、M≤100000,K≤32

Output
对于操作②每个输出一行,如题目所述。

Sample Input
3 3 3
2 7 3
1 2
2 3
Query 2 3
Replace 1 3
Query 1 1

Sample Output
4
7

这题思维难度挺大。。。因为nand不满足结合律,所以甚是难受。。。
但是网上介绍了一个叫做拆位的方法
首先树链剖分,然后对于每一位,都用线段树维护tl[t][p],代表如果该位是t,从左边过来这个区间后会变成什么数;tr[t][p]代表如果该位是t,从右边过来这个区间后会变成什么数,然后就可以从a到lca再到b询问就好了

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+'0');
}
const int N=1e5,K=33;
int ID[N+10],dfn[N+10],n,m,k;
ui v[N+10];
struct Segment{
    #define ls (p<<1)
    #define rs (p<<1|1)
    bool tr[2][(N<<2)+10],tl[2][(N<<2)+10];
    void updata(int p){
        tl[0][p]=tl[tl[0][ls]][rs],tr[0][p]=tr[tr[0][rs]][ls];
        tl[1][p]=tl[tl[1][ls]][rs],tr[1][p]=tr[tr[1][rs]][ls];
    }
    void build(int p,int l,int r,int x){
        if (l==r){
            tl[0][p]=1,tl[1][p]=!((v[dfn[l]]>>x)&1);
            tr[0][p]=1,tr[1][p]=!((v[dfn[l]]>>x)&1);
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid,x),build(rs,mid+1,r,x);
        updata(p);
    }
    void change(int p,int l,int r,int x,bool v){
        if (l==r){
            tl[0][p]=1,tl[1][p]=!v;
            tr[0][p]=1,tr[1][p]=!v;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) change(ls,l,mid,x,v);
        else    change(rs,mid+1,r,x,v);
        updata(p);
    }
    bool ql(int p,int l,int r,int x,int y,bool z){
        if (x<=l&&r<=y) return tl[z][p];
        int mid=(l+r)>>1;
        if (y<=mid) return ql(ls,l,mid,x,y,z);
        if (x>mid)  return ql(rs,mid+1,r,x,y,z);
        return ql(rs,mid+1,r,x,y,ql(ls,l,mid,x,y,z));
    }
    bool qr(int p,int l,int r,int x,int y,int z){
        if (x<=l&&r<=y) return tr[z][p];
        int mid=(l+r)>>1;
        if (y<=mid) return qr(ls,l,mid,x,y,z);
        if (x>mid)  return qr(rs,mid+1,r,x,y,z);
        return qr(ls,l,mid,x,y,qr(rs,mid+1,r,x,y,z));
    }
}Tree[K];
struct S1{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,cnt;
    int fa[N+10],size[N+10],deep[N+10],top[N+10],Rem[N+10],stack[N+10];
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void dfs1(int x,int Deep){
        deep[x]=Deep,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x;
            dfs1(son,Deep+1);
            size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void dfs2(int x){
        if (!x) return;
        dfn[ID[x]=++cnt]=x;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        dfs2(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            dfs2(son);
        }
    }
    void work(int x,int y){
        ui res=0; int Top=0;
        while (top[x]!=top[y]){
            if (deep[top[x]]>=deep[top[y]]){
                for (int i=0;i<k;i++)   res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[top[x]],ID[x],(res>>i)&1)<<i);
                x=fa[top[x]];
            }else   stack[++Top]=y,y=fa[top[y]];
        }
        for (int i=0;i<k;i++){
            if (deep[x]<deep[y])    res=res-(res&(1<<i))+(Tree[i].ql(1,1,n,ID[x],ID[y],(res>>i)&1)<<i);
            else    res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[y],ID[x],(res>>i)&1)<<i);
        }
        for (int i=Top;i;i--)   for (int j=0;j<k;j++)   res=res-(res&(1<<j))+(Tree[j].ql(1,1,n,ID[top[stack[i]]],ID[stack[i]],(res>>j)&1)<<j);
        printf("%u\n",res);
    }
}T;
int main(){
    n=read(),m=read(),k=read();
    for (int i=1;i<=n;i++)  scanf("%u",&v[i]);
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        T.insert(x,y);
    }
    T.dfs1(1,1),T.dfs2(1);
    for (int i=0;i<k;i++)   Tree[i].build(1,1,n,i);
    char s[10];
    for (int i=1;i<=m;i++){
        scanf("%s",s);
        if (s[0]=='R'){
            int x=read();scanf("%u",&v[x]);
            for (int j=0;j<k;j++)   Tree[j].change(1,1,n,ID[x],(v[x]>>j)&1);
        }
        if (s[0]=='Q'){
            int x=read(),y=read();
            T.work(x,y);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/9459821.html