• BZOJ4811 [Ynoi2017]由乃的OJ 树链剖分


    原文链接http://www.cnblogs.com/zhouzhendong/p/8085286.html 


    题目传送门 - BZOJ4811


    题意概括

      是BZOJ3668长在树上并加上修改和区间询问。

      一棵树,n个节点,每一个节点有一个位运算符和一个运算数。

      现在要你支持两种操作:

      1. 单点修改。

      2. 现在你有一个数字v,让他从x走到y,每到达一个节点进行相应的运算。v在0~z之间,让你使得运算结果最大,问v为何值。


    题解

      我们考虑树链剖分+线段树。

      假设某一位为0或者1,那么经过一定的操作之后也是0或1.

      那么,如果只有一位,那么两段就可以轻松合并了。

      k位也是一样,我们只需要用一堆奇怪的位运算就可以了,详见代码。

      要维护正的和反的。然后好像没什么要说的了。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef unsigned long long ULL;
    const int N=100005;
    struct Gragh{
    	int cnt,y[N*2],nxt[N*2],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m,k,op[N];
    int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],cnp=0;
    ULL Mod,val[N],n0=0,n1=~0;
    void Get_Gen_Info(int rt,int pre,int d){
    	size[rt]=1,son[rt]=-1,fa[rt]=pre,depth[rt]=d;
    	for (int i=g.fst[rt];i;i=g.nxt[i])
    		if (g.y[i]!=pre){
    			int s=g.y[i];
    			Get_Gen_Info(s,rt,d+1);
    			size[rt]+=size[s];
    			if (son[rt]==-1||size[s]>size[son[rt]])
    				son[rt]=s;
    		}
    }
    void Get_Top(int rt,int tp){
    	top[rt]=tp;
    	ap[p[rt]=++cnp]=rt;
    	if (!~son[rt])
    		return;
    	Get_Top(son[rt],tp);
    	for (int i=g.fst[rt];i;i=g.nxt[i]){
    		int s=g.y[i];
    		if (s!=fa[rt]&&s!=son[rt])
    			Get_Top(s,s);
    	}
    }
    struct STree{
    	ULL L0,R0,L1,R1;
    	STree (){}
    	STree (int x){L0=R0=0,L1=R1=-1;}
    	STree (ULL a,ULL b,ULL c,ULL d){L0=a,R0=b,L1=c,R1=d;}
    	void rev(){swap(L0,R0),swap(L1,R1);}
    	void suit(){L0&=(Mod-1),L1&=(Mod-1),R0&=(Mod-1),R1&=(Mod-1);}
    }t[N*4];
    STree operator + (STree a,STree b){
    	STree ans;
    	ans.L0=((~a.L0)&b.L0)|(a.L0&b.L1);
    	ans.L1=((~a.L1)&b.L0)|(a.L1&b.L1);
    	ans.R0=((~b.R0)&a.R0)|(b.R0&a.R1);
    	ans.R1=((~b.R1)&a.R0)|(b.R1&a.R1);
    	return ans;
    }
    void build(int rt,int L,int R){
    	if (L==R){
    		int o=op[ap[L]];
    		ULL v=val[ap[L]];
    		if (o==1)t[rt].L0=t[rt].R0=n0&v,t[rt].L1=t[rt].R1=n1&v;
    		if (o==2)t[rt].L0=t[rt].R0=n0|v,t[rt].L1=t[rt].R1=n1|v;
    		if (o==3)t[rt].L0=t[rt].R0=n0^v,t[rt].L1=t[rt].R1=n1^v;
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,L,mid);
    	build(rs,mid+1,R);
    	t[rt]=t[ls]+t[rs];
    }
    void change(int rt,int L,int R,int pos,int o,ULL v){
    	if (L==R){
    		if (o==1)t[rt].L0=t[rt].R0=n0&v,t[rt].L1=t[rt].R1=n1&v;
    		if (o==2)t[rt].L0=t[rt].R0=n0|v,t[rt].L1=t[rt].R1=n1|v;
    		if (o==3)t[rt].L0=t[rt].R0=n0^v,t[rt].L1=t[rt].R1=n1^v;
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	if (pos<=mid)
    		change(ls,L,mid,pos,o,v);
    	else
    		change(rs,mid+1,R,pos,o,v);
    	t[rt]=t[ls]+t[rs];
    }
    STree query(int rt,int L,int R,int xL,int xR){
    	if (R<xL||L>xR)
    		return STree(0);
    	if (xL<=L&&R<=xR)
    		return t[rt];
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	return query(ls,L,mid,xL,xR)+query(rs,mid+1,R,xL,xR);
    }
    ULL Tquery(int a,int b,ULL z){
    	int f1=top[a],f2=top[b],rev=0;
    	STree ansa(0),ansb(0);
    	while (f1!=f2){
    		if (depth[f1]<depth[f2])
    			swap(f1,f2),swap(a,b),swap(ansa,ansb),rev^=1;
    		ansa=query(1,1,n,p[f1],p[a])+ansa;
    		a=fa[f1],f1=top[a];
    	}
    	if (depth[a]>depth[b])
    		swap(a,b),swap(ansa,ansb),rev^=1;
    	ansa.rev();
    	STree ans=ansa+query(1,1,n,p[a],p[b])+ansb;
    	if (rev)
    		ans.rev();
    	ULL ansv=0;
    //	ans.suit();
    	for (int i=k;~i;i--){
    		if (ans.L0&(1ULL<<i))
    			ansv|=1ULL<<i;
    		else if (z>=(1ULL<<i)&&(ans.L1&(1ULL<<i)))
    			ansv|=1ULL<<i,z-=1ULL<<i;
    	}
    	return ansv;
    }
    int main(){
    	g.clear();
    	scanf("%d%d%d",&n,&m,&k);
    	for (int i=1;i<=n;i++)
    		scanf("%d%llu",&op[i],&val[i]);
    	Mod=1ULL<<k;
    	for (int i=1,a,b;i<n;i++){
    		scanf("%d%d",&a,&b);
    		g.add(a,b),g.add(b,a);
    	}
    	Get_Gen_Info(1,0,0);
    	Get_Top(1,1);
    	build(1,1,n);
    	for (int i=1;i<=m;i++){
    		int op,x,y;
    		ULL z;
    		scanf("%d%d%d%llu",&op,&x,&y,&z);
    		if (op==1)
    			printf("%llu
    ",Tquery(x,y,z));
    		else
    			change(1,1,n,p[x],y,z);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    正则表达式
    模块初阶
    面向对象的一些理论表述,涉及知识的理解和内置方法
    面向对象的反射 和 特殊内置方法
    面向对象的属性,类方法.静态变量
    面向对象的 多态,
    面向对象的继承属性
    面向对象组合思想的经典题
    面向对象,类名称空间查找顺序 和组合
    jQuery对象与DOM对象之间的转换
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4811.html
Copyright © 2020-2023  润新知