[Luogu 3613] 睡觉困难综合征

Description

给定一棵 \(n\) 个点的树,每个点上有位运算 \(opt\) 和一个权值 \(x\),位运算有 &,|,^ 三种。

要求支持:

  1. 修改点 \(v\)\(opt\)\(x_v\)
  2. 确定一个初始点权在 \([0,z]\) 之间的 \(v_0\),然后依次经过从 \(x\)\(y\) 的所有节点。每经过一个节点 \(i\)\(v\) 就变成 \(v\;opt\;x_i\) 请回答最后到 \(y\) 时可能的最大的 \(v\)

Solution

首先五十分的做法比较显然,就是拆位建 \(lct\),然后每位分开做,复杂度 \(O(nk\log n)\)

这样只有 \(50\) 分,考虑优化复杂度。

因为 \(O(n\log n)\) 已经是 \(lct\) 的复杂度了不是很能优化掉,考虑去掉复杂度乘上的 \(k\)

有这个 \(k\) 的原因是我们对于每一位都搞了棵 \(lct\) 出来。如果我们只弄一棵 \(lct\) 是否可行呢?

定义 \(f0,f1\) 分别为初始值全 \(0/1\) 走过一条路径之后的答案

那在 \(lct\) 中需要维护的就是 \(splay\)\(x\) 的子树,中序遍历的 \(f0,f1\) 已经倒着的中序遍历(与中序遍历相反)\(f0,f1\) (要维护这个倒着的原因是当前点 \(x\) 的值与左右子树的顺序有关,而 \(splay\) 中又有 \(reverse\) 操作所以要维护)。

那有了这个能不能快速更新呢?也就是说有左区间的 \(f0,f1\) 和右区间的 \(g0,g1\),能不能快速求出来 \(h0,h1\) 呢?废话

更新式子比较显然就是:\(h0=(f0\&g1)+(\sim f0\& g0),h1=(f1\And g1)+(\sim f1\& g0)\)

证明的话就是全 \(0\) 放进去左区间之后跑出来的是 \(f0\),可能长 \(10010001010\) 这样,然后再去 $\And $ 一下 \(g1\) 就代表这些当前为 \(1\) 的位放进右区间之后跑出来的是多少。因为 \(\&\)\(f0\) 所以最后答案肯定不会比 \(f0\) 大。其它几项的证明也类似就不去证了。

最后求出来 从 \(x\)\(y\)\(f0,f1\) 之后贪心的选就好了。

Code

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef unsigned long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)

namespace NewweN{
    
    const int N=1e5+5;

    int n,m,cnt,head[N],stk[N],top;
    int fa[N],ch[N][2],tag[N],k;ll maxn;
    char buf[1048578];int ptr,MX;
    #define ls ch[x][0]
    #define rs ch[x][1]

    struct Edge{
        int to,nxt;
    }edge[N<<1];

    void add(int x,int y){
        edge[++cnt].to=y;
        edge[cnt].nxt=head[x];
        head[x]=cnt;
    }

    struct Node{
        ll a,b;
        Node(){}
        Node(ll x,ll y){
            a=x,b=y;
        }
        friend Node operator+(Node x,Node y){
            return Node((x.a&y.b)+(((~x.a))&y.a),(x.b&y.b)+(((~x.b))&y.a));
        }
    }l[N],r[N],val[N];
    
    char nc(){
        if(ptr==MX) MX=fread(buf,1,1<<20,stdin),ptr=0;
        return ptr==MX?EOF:buf[ptr++];
    }
    #define getchar nc
    ll getint(){
        ll X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }

    void dfs(int now,int f=0){
        for(int i=head[now];i;i=edge[i].nxt){
            int to=edge[i].to;
            if(to==f)continue;
            fa[to]=now;
            dfs(to,now);
        }
    }

    void pushup(int x){
        l[x]=r[x]=val[x];
        if(ls)l[x]=l[ls]+l[x],r[x]=r[x]+r[ls];
        if(rs)l[x]=l[x]+l[rs],r[x]=r[rs]+r[x];
    }

    void pushr(int x){
        tag[x]^=1;swap(ls,rs);swap(l[x],r[x]);
    }

    void pushdown(int x){
        if(tag[x])tag[x]=0,pushr(ls),pushr(rs);
    }

    bool nroot(int x){
        return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
    }

    void rotate(int x){
        int y=fa[x],z=fa[y],d=ch[y][1]==x,dd=ch[z][1]==y;
        ch[y][d]=ch[x][d^1];if(ch[x][d^1])fa[ch[x][d^1]]=y;
        fa[x]=z;if(nroot(y))ch[z][dd]=x;
        fa[y]=x;ch[x][d^1]=y;pushup(y);
    }

    void splay(int x){
        int now=x;stk[++top]=now;
        while(nroot(now))now=fa[now],stk[++top]=now;
        while(top)pushdown(stk[top--]);
        while(nroot(x)){
            int y=fa[x],z=fa[y];
            if(nroot(y))rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
            rotate(x);
        }pushup(x);
    }

    void access(int x){
        for(int y=0;x;y=x,x=fa[x]){
            splay(x);rs=y;
            pushup(x);
        }
    }

    void makeroot(int x){
        access(x),splay(x),pushr(x);
    }

    void split(int x,int y){
        makeroot(x),access(y),splay(y);
    }

    signed main(){
        n=getint(),m=getint(),k=getint();
        maxn=(1ull<<k)-1;
        for(int i=1;i<=n;i++){
            ll x=getint(),y=getint();
            if(x==1)val[i]=Node(0,y);
            if(x==2)val[i]=Node(y,~0);
            if(x==3)val[i]=Node(y,(~y));
        }
        for(int i=1;i<n;i++){
            int x=getint(),y=getint();
            add(x,y),add(y,x);
        } dfs(1);
        while(m--){
            int opt=getint(),x=getint(),y=getint();ll z=getint();
            if(opt==1){
                split(x,y);
                ll ans=0,used=0;
                for(int i=k-1;~i;i--){
                    if(l[y].a>>i&1ull) ans|=1ull<<i;
                    else if((l[y].b>>i&1ull) and (used|(1ull<<i))<=z) ans|=1ull<<i,used|=1ull<<i;
                } printf("%llu\n",ans);
            } else{
                splay(x);
                if(y==1) val[x]=Node(0,z);
                if(y==2) val[x]=Node(z,~0);
                if(y==3) val[x]=Node(z,(~z));
                pushup(x);
            }
        } return 0;
    }
}

int yzh=NewweN::main();

signed main(){return 0;}
posted @ 2018-11-26 21:23  YoungNeal  阅读(177)  评论(0编辑  收藏  举报