• [Ynoi2017]由乃的OJ


    题意

    由乃正在做她的OJ。现在她在处理OJ上的用户排名问题。OJ上注册了n个用户,编号为1~",一开始他们按照编号
    排名。由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天
    天问她题。。。因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她
    在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送
    Deus:这个题怎么做呀?
    yuno:这个不是NOI2014的水题吗。。。
    Deus:那如果出到树上,多组链询问,带修改呢?
    yuno:诶。。。???
    Deus:这题叫做睡觉困难综合征哟~
    虽然由乃OI很好,但是她基本上不会DS,线段树都只会口胡,比如她NOI2016的分数就是100+100+100+0+100+100。
    。。NOIP2017的分数是100+0+100+100+0+100所以她还是只能找你帮她做了。。。
    给你一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示。
    每次询问包含三个数x,y,z,初始选定一个数v。然后v依次经过从x到y的所有节点,每经过一个点i,v就变成v opti
    xi,所以他想问你,最后到y时,希望得到的值尽可能大,求最大值?给定的初始值v必须是在[0,z]之间。每次修
    改包含三个数x,y,z,意思是把x点的操作修改为y,数值改为z

    0 <= n , m <= 100000 , k <= 64

    分析

    参照clover_hxy的题解。

    这道题与Noi2014起床困难综合症 十分类似。同样的每一位也是互补影响的,那么最基础的思路就是对于每一位分开维护,对于树进行树链剖分,对于线段树中的区间维护以0,1打头从左到右和从右到左分别计算出的答案。

    但是单纯的这么做时间复杂度非常多。所以我们考虑将每一位压到一个unsigned long long 中。对于最底层的节点我们之间计算他的点值和运算符。考虑上面区间的维护,假设左区间以0开头的每一位得到的答案是011,那么如果要合并的答案的话,第一位是0,应该接右区间以0开头该位得到的答案。 以1开头的从左到右为例,那么合并其实就是(l.v1&r.v1)|((~l.v1)&r.v0))

    时间复杂度(O(n + m (log^2 n + log v)))

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
    	rg T data=0,w=1;
    	rg char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    		data=data*10+ch-'0',ch=getchar();
    	return data*w;
    }
    template<class T>il T read(rg T&x){
    	return x=read<T>();
    }
    typedef unsigned long long ULL;
    using namespace std;
    
    co ULL mx=0-1;
    co int N=2e5;
    int opt[N],n,m,k,point[N],nxt[N],v[N],belong[N],son[N];
    int fa[N],size[N],pos[N],tot,deep[N],q[N],sz;
    ULL val[N],mi[N];
    struct data{
    	ULL v0,v1,w0,w1;
    }tr[N*4],ans[N],ans1[N];
    void add(int x,int y){
    	++tot,nxt[tot]=point[x],point[x]=tot,v[tot]=y;
    	++tot,nxt[tot]=point[y],point[y]=tot,v[tot]=x;
    }
    void dfs(int x,int f){
    	size[x]=1,deep[x]=deep[f]+1;
    	for(int i=point[x];i;i=nxt[i]){
    		if(v[i]==f) continue;
    		fa[v[i]]=x;
    		dfs(v[i],x);
    		size[x]+=size[v[i]];
    		if(size[v[i]]>size[son[x]]) son[x]=v[i];
    	}
    }
    void dfs1(int x,int chain){
    	belong[x]=chain,pos[x]=++sz,q[sz]=x;
    	if(!son[x]) return;
    	dfs1(son[x],chain);
    	for(int i=point[x];i;i=nxt[i])
    		if(v[i]!=son[x]&&v[i]!=fa[x]) dfs1(v[i],v[i]);
    }
    ULL calc(ULL num,int x){
    	if(opt[x]==1) return num&val[x];
    	if(opt[x]==2) return num|val[x];
    	if(opt[x]==3) return num^val[x];
    }
    data update(co data&l,co data&r){
    	data now;
    	now.v0=(l.v0&r.v1)|(~l.v0&r.v0);
    	now.v1=(l.v1&r.v1)|(~l.v1&r.v0);
    	now.w0=(r.w0&l.w1)|(~r.w0&l.w0);
    	now.w1=(r.w1&l.w1)|(~r.w1&l.w0);
    	return now;
    }
    void build(int now,int l,int r){
    	if(l==r){
    		int t=q[l];
    		tr[now].v0=tr[now].w0=calc(0,t);
    		tr[now].v1=tr[now].w1=calc(mx,t);
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(now<<1,l,mid);
    	build(now<<1|1,mid+1,r);
    	tr[now]=update(tr[now<<1],tr[now<<1|1]);
    }
    void pointchange(int now,int l,int r,int x){
    	if(l==r){
    		int t=q[l];
    		tr[now].v0=tr[now].w0=calc(0,t);
    		tr[now].v1=tr[now].w1=calc(mx,t);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(x<=mid) pointchange(now<<1,l,mid,x);
    	else pointchange(now<<1|1,mid+1,r,x);
    	tr[now]=update(tr[now<<1],tr[now<<1|1]);
    }
    data query(int now,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr) return tr[now];
    	int mid=(l+r)>>1;
    	if(qr<=mid) return query(now<<1,l,mid,ql,qr);
    	if(ql>mid) return query(now<<1|1,mid+1,r,ql,qr);
    	return update(query(now<<1,l,mid,ql,qr),query(now<<1|1,mid+1,r,ql,qr));
    }
    data solve(int x,int y){
    	int cnt=0,cnt1=0;
    	while(belong[x]!=belong[y]){
    		if(deep[belong[x]]>deep[belong[y]]){
    			ans[++cnt]=query(1,1,n,pos[belong[x]],pos[x]);
    			x=fa[belong[x]];
    		}
    		else{
    			ans1[++cnt1]=query(1,1,n,pos[belong[y]],pos[y]);
    			y=fa[belong[y]];
    		}
    	}
    	if(deep[x]<deep[y]) ans1[++cnt1]=query(1,1,n,pos[x],pos[y]);
    	else ans[++cnt]=query(1,1,n,pos[y],pos[x]);
    	for(int i=1;i<=cnt;++i)
    		swap(ans[i].v0,ans[i].w0),swap(ans[i].v1,ans[i].w1);
    	data sum;
    	if(cnt){
    		sum=ans[1];
    		for(int i=2;i<=cnt;++i)
    			sum=update(sum,ans[i]);
    		if(cnt1) sum=update(sum,ans1[cnt1]);
    	}
    	else sum=ans1[cnt1];
    	for(int i=cnt1-1;i>=1;--i)
    		sum=update(sum,ans1[i]);
    	return sum;
    }
    int main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n),read(m),read(k);
    	mi[0]=1;
    	for(int i=1;i<k;++i)
    		mi[i]=mi[i-1]<<1;
    	for(int i=1;i<=n;++i)
    		read(opt[i]),read(val[i]);
    	for(int i=1;i<n;++i)
    		add(read<int>(),read<int>());
    	dfs(1,0),dfs1(1,1);
    	build(1,1,n);
    	for(int i=1;i<=m;++i){
    		int op=read<int>(),x=read<int>(),y=read<int>();
    		ULL z=read<ULL>();
    		if(op==2){
    			opt[x]=y,val[x]=z;
    			pointchange(1,1,n,pos[x]);
    		}
    		else{
    			data t=solve(x,y);
    			ULL ans=0;
    			for(int i=63;i>=0;--i){
    				ULL t0=t.v0>>i&1,
    					t1=t.v1>>i&1;
    				if(t0>=t1||mi[i]>z) ans|=(t0?mi[i]:0);
    				else ans|=(t1?mi[i]:0),z-=mi[i];
    			}
    			printf("%llu
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    虚拟机VirtualBox 共享挂载问题:mount: /mnt/xxx: wrong fs type, bad option, bad superblock on xxx
    git 设置和取消代理
    (转载)数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知
    关于golang中IO相关的Buffer类浅析
    (转)golang获取当前时间、时间戳和时间字符串及它们之间的相互转换
    FFmpeg常用命令
    go cmd nohup 的坑
    Nginx配置详解(转)
    记录一次go性能调试的过程
    github徽标引入
  • 原文地址:https://www.cnblogs.com/autoint/p/10408152.html
Copyright © 2020-2023  润新知