• BZOJ4811 [Ynoi2017]由乃的OJ


    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ4811

    正解:树链剖分+线段树

    解题报告:

      因为位与位之间互相独立,考虑直观做法,对于每一位维护两个变量,分别表示这一位输入$0$、$1$之后会变成的值。

      这个复杂度是$O(knlog^2n)$,显然不能通过。

      但是我们不难发现,对于不同的位,其$0$、$1$的变化趋势相同,那么可以用位运算优化, 把每个输入$0$、$1$压成两个二进制数,每次的变化可以变成位运算。

      仔细考虑一下含义,不妨设为$x$、$y$两个变量合并。

      那么$x$的$0$最终会变成的值,应该是$0$变成$1$再从$1$变成$0$,或上$0$保持$0$的情况。想想就能推出来了==

      注意合并顺序。

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <queue>
    #include <cmath>
    #include <ctime>
    #define lc root<<1
    #define rc root<<1|1
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define reg(i,x) for(int i=first[x];i;i=nxt[i])
    using namespace std;
    typedef unsigned long long LL;
    const int MAXN = 200011;
    const int MAXM = 400011;
    int n,m,Type[MAXN],ecnt,first[MAXN],nxt[MAXM],to[MAXM],son[MAXN],size[MAXN],top[MAXN],dfn[MAXN],pre[MAXN],deep[MAXN],ql,qr,father[MAXN];
    LL chu[MAXN],k,A,mi[100];
    bool ok;
    struct node{ LL ans0,ans1; }a[MAXN*3],b[MAXN*3],ans,ansx,ansy,tmp;
    inline void link(int x,int y){ nxt[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
    inline node merge(node q,node qq){ return (node){(q.ans0&qq.ans1) | (~q.ans0&qq.ans0) , (q.ans1&qq.ans1) | (~q.ans1&qq.ans0)}; }
    inline LL getint(){
        LL w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline node get(int tt,LL z){
    	if(tt==1) return (node){ 0,(~0)&z };
    	else if(tt==2) return (node){ z,(~0)|z };
    	else return (node){ z,(~0)^z };
    }
    
    inline void dfs(int x,int fa){
    	size[x]=1;
    	reg(i,x) {
    		int v=to[i]; if(v==fa) continue;
    		deep[v]=deep[x]+1; father[v]=x; dfs(v,x);
    		size[x]+=size[v]; if(size[v]>size[son[x]]) son[x]=v;
    	}
    }
    
    inline void dfs2(int x,int fa){
    	dfn[x]=++ecnt; pre[ecnt]=x; if(son[x]) top[son[x]]=top[x],dfs2(son[x],x);
    	reg(i,x) {
    		int v=to[i]; if(v==fa || v==son[x]) continue;
    		top[v]=v; dfs2(v,x);
    	}
    }
    
    inline void build(int root,int l,int r){
    	if(l==r) {
    		int x=pre[l];
    		a[root]=b[root]=get(Type[x],chu[x]);
    		return ;
    	}
    	int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r);
    	a[root]=merge(a[lc],a[rc]);
    	b[root]=merge(b[rc],b[lc]);
    }
    
    inline void modify(int root,int l,int r,int pos,int tt,LL z){
    	if(l==r) {
    		a[root]=get(tt,z);
    		b[root]=get(tt,z);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(pos<=mid) modify(lc,l,mid,pos,tt,z);
    	else modify(rc,mid+1,r,pos,tt,z);
    	a[root]=merge(a[lc],a[rc]);
    	b[root]=merge(b[rc],b[lc]);
    }
    
    inline void query(int root,int l,int r,int type){
    	if(ql<=l && r<=qr) {
    		if(!ok) {
    			ok=true;
    			tmp=type?a[root]:b[root];
    		}
    		else {
    			if(type) tmp=merge(tmp,a[root]);
    			else tmp=merge(tmp,b[root]);
    		}
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(qr<=mid) query(lc,l,mid,type);
    	else if(ql>mid) query(rc,mid+1,r,type);
    	else {
    		if(type) query(lc,l,mid,type),query(rc,mid+1,r,type);//down y!!!
    		else query(rc,mid+1,r,type),query(lc,l,mid,type);//up x!!!
    	}
    }
    
    inline void lca(int x,int y){
    	int f1=top[x],f2=top[y]; 
    	bool flag1=false,flag2=false;
    	while(f1!=f2) {
    		if(deep[f1]<deep[f2]) {
    			ql=dfn[f2]; qr=dfn[y]; ok=false;
    			query(1,1,n,1);
    			y=father[f2]; f2=top[y];
    			if(!flag2) ansy=tmp,flag2=true;
    			else ansy=merge(tmp,ansy);
    		}
    		else {
    			ql=dfn[f1]; qr=dfn[x]; ok=false;
    			query(1,1,n,0);
    			x=father[f1]; f1=top[x];
    			if(!flag1) ansx=tmp,flag1=true;
    			else ansx=merge(ansx,tmp);
    		}
    	}
    	if(deep[x]<deep[y]) {
    		ql=dfn[x]; qr=dfn[y]; ok=false;
    		query(1,1,n,1);
    		if(!flag2) ansy=tmp,flag2=true;//!!!
    		else ansy=merge(tmp,ansy);
    	}
    	else {
    		ql=dfn[y]; qr=dfn[x]; ok=false;
    		query(1,1,n,0);
    		if(!flag1) ansx=tmp,flag1=true;//!!!
    		else ansx=merge(ansx,tmp);
    	}
    	if(!flag1) ans=ansy;
    	else if(!flag2) ans=ansx;
    	else ans=merge(ansx,ansy);
    }
    
    inline void work(){
    	n=getint(); m=getint(); k=getint(); for(int i=1;i<=n;i++) Type[i]=getint(),chu[i]=getint();
    	int type,x,y; LL z,now; for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); }
    	deep[1]=1; dfs(1,0);
    	ecnt=0; dfs2(1,0);
    	build(1,1,n);
    	mi[0]=1; for(int i=1;i<=64;i++) mi[i]=mi[i-1]*2;
    	while(m--) {
    		type=getint();
    		if(type==1) {
    			x=getint(); y=getint(); z=getint();
    			lca(x,y); 
    			A=0; now=0;
    			for(long long i=k;i>=0;i--) {
    				if((ans.ans0>>i)&1) A+=mi[i];
    				else if(( ans.ans1>>i &1 ) && (now+mi[i]<=z)){
    					A+=mi[i];
    					now+=mi[i];
    				}
    			}
    			//cout<<A<<endl;
    			printf("%llu
    ",A);
    		}
    		else {
    			x=getint(); y=getint(); z=getint();
    			modify(1,1,n,dfn[x],y,z);
    		}
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("4811.in","r",stdin);
    	freopen("4811.out","w",stdout);
    #endif
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    3.25Java常量
    3.26Java逻辑运算符
    3.26Java关系运算符
    Java标识符
    3.27Java位运算符
    3.26Java运算符(operator)
    3.26Java字符型(char)变量、常量
    3.26Java布尔类型(boolean)变量、常量
    《算法导论》第9章 顺序统计学 (1)最小值和最大值
    《算法导论》第8章 线性时间排序 (1)计数排序
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6701564.html
Copyright © 2020-2023  润新知