睡觉困难综合征,洛谷P3613,树链剖分+树上较复杂合并

正题

      一看到这题就心碎emm,好好睡觉不行吗。。。

      关键看完这道题,你就要想到,用树链剖分+线段树来维护,因为在这方面线段树是最灵活而且是最万能的。我们就要想,怎么去进行线段树合并。

      首先,您不可能建2^64个线段树。然后第i个线段树维护i经过这个线段树的某个区间所留下来的值。

      这样的时间复杂的虽然比起暴力来好像快很多,但是细想还是不行。

      想着拆位优化。

      比如说当前的z是00101001.

      那么我们就可以取00000000~00101001.

      位运算就是每一位之间的操作都不影响,所以我们可以把它们拆成一位一位进去跑。

      如果第一位(最高位)放入一个0,跑出来的结果是0.

      放入一个1,跑出来的结果是1.

      那么我们肯定会优先选择有价值的,因为我们是从高位往底位做,所以就算后面的1全部取,也没有当前取1大,所以当前优先取大。

      那么我们对于每一个位置建立一棵线段树,然后进行维护。跑一遍合并之后发现我们的时间复杂度为

      m logn logn 64*2

     所以是接近1亿的。

     那么我们都说了,不同两位之间不会影响,何尝不把它们同时做,用unsigned long long 来存储呢?

     那么我们之前是对于每一位放0和放1跑,现在我们不如放000000...和111111...来跑。

    所以线段树中的每一个节点都只需要存两个值,一个是000000...放进该区间跑出来的权值,另一个是111111...放进该区间跑出来的权值。

     然后我们就发现,在向上维护的过程中遇到了麻烦。

     比如说00000000放入左子树跑出来的答案是01001011.

     但是右子树的节点只存储了两个值00000000放进去跑和11111111放进去跑。

     那么我们怎么向上维护呢?

     我们需要做的是不是将左子树中的1,改成这一位为1时放入右子树后的得出来的值。

     那么得出来的一个unsigned long long 我们把它设为ans

     ans中为1的条件是什么?

     左子树的答案中为1的那位,在右子树把1放进去时也为1.

     左子树的答案中为0的那位,在右子树把0放进去时也为1

     所以思考一下位运算,就可以作出O(1)的向上维护

    ans[now][0]=(ans[rs[now]][1]&ans[ls[now]][0])|(ans[rs[now]][0]&(~ans[ls[now]][0]));
    ans[now][1]=(ans[rs[now]][1]&ans[ls[now]][1])|(ans[rs[now]][0]&(~ans[ls[now]][1]));

      然后依据这个来更新就可以了,这部分是关键哦~

     另外还要说的,因为位运算的操作不能颠倒,所以必须从x往y做。

     所以我们做的顺序可能是(7->1) (8->11)

     顺序就会有正和倒的区分,所以要建两棵线段树。

     最后把得出来的两个值(分别是把000...放进去和把111...放进去的权值)

     做一遍贪心(上面),就可以知道最大的v。

    

// luogu-judger-enable-o2
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int ls[1000010],rs[1000010];//0为从左往右放,1为从右往左放 
unsigned long long ans[1000010][2][2];
int root;
int n,m,k;
unsigned long long t[100010];
int op[200010];
struct edge{
    int y,next;
}u[200010];
int first[200010];
int tot[200010],son[200010],top[200010],image[200010],fa[200010],dep[200010];
int len=0;
int v,opt;
unsigned long long tt;
unsigned long long piece=0-1;

void ins(int x,int y){
    len++;
    u[len].y=y;u[len].next=first[x];first[x]=len;
}

void dfs_1(int x){
    tot[x]=1;
    for(int i=first[x];i!=0;i=u[i].next){
        int y=u[i].y;
        if(y!=fa[x]){
            fa[y]=x;
            dep[y]=dep[x]+1;
            dfs_1(y);
            if(tot[y]>tot[son[x]]) son[x]=y;
            tot[x]+=tot[y];
        }
    }
}

void dfs_2(int x,int tp){
    top[x]=tp;image[x]=++len;
    if(son[x]!=0) dfs_2(son[x],tp);
    for(int i=first[x];i!=0;i=u[i].next){
        int y=u[i].y;
        if(y!=fa[x] && y!=son[x]) dfs_2(y,y);
    }
}

void update(int&now,int x,int y){
    if(now==0) now=++len;
    int mid=(x+y)/2;
    if(x==y){
        if(opt==1){
            ans[now][0][0]=ans[now][0][1]=(0&tt);
            ans[now][1][0]=ans[now][1][1]=(piece&tt);
        }
        else if(opt==2){
            ans[now][0][0]=ans[now][0][1]=(0|tt);
            ans[now][1][0]=ans[now][1][1]=(piece|tt);
        }
        else if(opt==3){
            ans[now][0][0]=ans[now][0][1]=(0^tt);
            ans[now][1][0]=ans[now][1][1]=(piece^tt);
        }
        return ;
    }
    if(v<=mid) update(ls[now],x,mid);
    else update(rs[now],mid+1,y);
    ans[now][0][0]=(ans[rs[now]][1][0]&ans[ls[now]][0][0])|(ans[rs[now]][0][0]&(~ans[ls[now]][0][0]));
    ans[now][1][0]=(ans[rs[now]][1][0]&ans[ls[now]][1][0])|(ans[rs[now]][0][0]&(~ans[ls[now]][1][0]));
    ans[now][0][1]=(ans[ls[now]][1][1]&ans[rs[now]][0][1])|(ans[ls[now]][0][1]&(~ans[rs[now]][0][1]));
    ans[now][1][1]=(ans[ls[now]][1][1]&ans[rs[now]][1][1])|(ans[ls[now]][0][1]&(~ans[rs[now]][1][1]));
}

unsigned long long get_change(int now,int l,int r,int x,int y,bool w,bool wh){
    if(l==x && r==y) return ans[now][w][wh];
    int mid=(x+y)/2;
    if(r<=mid) return get_change(ls[now],l,r,x,mid,w,wh);
    else if(mid<l) return get_change(rs[now],l,r,mid+1,y,w,wh);
    else{
    	unsigned long long temp;
        if(wh==false){
        	temp=get_change(ls[now],l,mid,x,mid,w,wh);
        	temp=(get_change(rs[now],mid+1,r,mid+1,y,true,wh)&temp)|(get_change(rs[now],mid+1,r,mid+1,y,false,wh)&(~temp));
        }
        else {
        	temp=get_change(rs[now],mid+1,r,mid+1,y,w,wh);
        	temp=(get_change(ls[now],l,mid,x,mid,true,wh)&temp)|(get_change(ls[now],l,mid,x,mid,false,wh)&(~temp));
        }
        return temp;
    }
}

int l[2][30],r[2][30];
int tota[2],total;

unsigned long long solve(){
    int x,y;
    unsigned long long z;
    scanf("%d %d %llu",&x,&y,&z);
    int tx=top[x],ty=top[y];
    bool tf=true;
    tota[0]=tota[1]=0;
    while(tx!=ty){
        if(dep[tx]>dep[ty]){
            swap(x,y);
            swap(tx,ty);
            tf^=true;
        }
        l[tf][++tota[tf]]=image[ty];
        r[tf][tota[tf]]=image[y];
        y=fa[ty];ty=top[y];
    }
    if(dep[x]>dep[y]){
        swap(x,y);
        tf^=true;
    }
    l[tf][++tota[tf]]=image[x];
    r[tf][tota[tf]]=image[y];
    unsigned long long op1=0,op2=0-1;
    for(int i=1;i<=tota[0];i++){
        op1=(get_change(root,l[0][i],r[0][i],1,n,true,true)&op1)|(get_change(root,l[0][i],r[0][i],1,n,false,true)&(~op1));
    	op2=(get_change(root,l[0][i],r[0][i],1,n,true,true)&op2)|(get_change(root,l[0][i],r[0][i],1,n,false,true)&(~op2));
    }
    for(int i=tota[1];i>=1;i--){
        op1=(get_change(root,l[1][i],r[1][i],1,n,true,false)&op1)|(get_change(root,l[1][i],r[1][i],1,n,false,false)&(~op1));
    	op2=(get_change(root,l[1][i],r[1][i],1,n,true,false)&op2)|(get_change(root,l[1][i],r[1][i],1,n,false,false)&(~op2));
    }
    unsigned long long temp=((unsigned long long)1<<63);
    unsigned long long vv=0;
    for(int i=63;i>=0;i--){
        if(op1&temp) vv+=temp;
        else if((op2&temp) && temp<=z){
            vv+=temp;
            z-=temp;
        }
    	temp>>=1;
    }
    return vv;
}

void change(){
    int x,y;
    unsigned long long z;
    scanf("%d %d %llu",&x,&y,&z);
    v=image[x];opt=y;
    tt=z;
    update(root,1,n);
}

int main(){
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%d %llu",&op[i],&t[i]);
    for(int i=1;i<=n-1;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        ins(x,y);
        ins(y,x);
    }
    dep[1]=1;dfs_1(1);
    len=0;dfs_2(1,1);
    len=0;
    for(int i=1;i<=n;i++){
        v=image[i];opt=op[i];
        tt=t[i];
        update(root,1,n);
    }
    int type;
    while(m--){
        scanf("%d",&type);
        if(type==1) printf("%llu\n",solve());
        else change();
    }
}



    

     

猜你喜欢

转载自blog.csdn.net/deep_kevin/article/details/80684392
今日推荐