1. 程式人生 > >【BZOJ4811】[Ynoi2017]由乃的OJ 樹鏈剖分+線段樹

【BZOJ4811】[Ynoi2017]由乃的OJ 樹鏈剖分+線段樹

size 數值 sin 分數 strong str blank cstring else

【BZOJ4811】[Ynoi2017]由乃的OJ

Description

由乃正在做她的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

Input

第一行三個數n,m,k。k的意義是每個點上的數,以及詢問中的數值z都 <2^k。之後n行 每行兩個數x,y表示該點的位運算編號以及數值 之後n - 1行,每行兩個數x,y表示x和y之間有邊相連 之後m行,每行四個數,Q,x,y,z表示這次操作為Q(1位詢問,2為修改),x,y,z意義如題所述 0 <= n , m <= 100000 , k <= 64

Output

對於每個操作1,輸出到最後可以造成的最大刺激度v

Sample Input

5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2

Sample Output

7
1
5

題解:思路同BZOJ2908又是nand,不過本題nlog3n顯然過不去,所以我們考慮優化我們的算法。

考慮能否不拆位,將所有位壓成一個unsigned long long一起盡行計算。設l0表示一個所有位都是0的數從左往右經過這段區間會變成什麽,l1表示一個所有位都是1的數從左往右經過這個點會變成什麽,那麽顯然有:

l0[x]=(l0[lson]&l1[rson])|((~l0[lson])&l0[rson])
l1[x]=(l1[lson]&l1[rson])|((~l1[lson])&l0[rson])

r0,r1同理,然後就是nlog2n的了。

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef unsigned long long ll;
const int maxn=100010;
int n,m,k,cnt;
ll msk;
ll l0[maxn<<2],l1[maxn<<2],r0[maxn<<2],r1[maxn<<2],v[maxn];
int to[maxn<<1],next[maxn<<1],head[maxn],dep[maxn],fa[maxn],top[maxn],son[maxn],siz[maxn],p[maxn],op[maxn],q[maxn];
int st[maxn];
void pushup(int x)
{
	l0[x]=(l0[lson]&l1[rson])|((~l0[lson])&l0[rson]);
	l1[x]=(l1[lson]&l1[rson])|((~l1[lson])&l0[rson]);
	r0[x]=(r0[rson]&r1[lson])|((~r0[rson])&r0[lson]);
	r1[x]=(r1[rson]&r1[lson])|((~r1[rson])&r0[lson]);
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		if(op[q[l]]==1)	l1[x]=r1[x]=v[q[l]],l0[x]=r0[x]=0;
		if(op[q[l]]==2)	l1[x]=r1[x]=msk,l0[x]=r0[x]=v[q[l]];
		if(op[q[l]]==3)	l1[x]=r1[x]=v[q[l]]^msk,l0[x]=r0[x]=v[q[l]];
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	pushup(x);
}
void updata(int l,int r,int x,int a,int op,ll val)
{
	if(l==r)
	{
		if(op==1)	l1[x]=r1[x]=val,l0[x]=r0[x]=0;
		if(op==2)	l1[x]=r1[x]=msk,l0[x]=r0[x]=val;
		if(op==3)	l1[x]=r1[x]=val^msk,l0[x]=r0[x]=val;
		return ;
	}
	int mid=l+r>>1;
	if(a<=mid)	updata(l,mid,lson,a,op,val);
	else	updata(mid+1,r,rson,a,op,val);
	pushup(x);
}
ll ql(int l,int r,int x,int a,int b,ll val)
{
	if(a<=l&&r<=b)	return (val&l1[x])|((~val)&l0[x]);
	int mid=l+r>>1;
	if(b<=mid)	return ql(l,mid,lson,a,b,val);
	if(a>mid)	return ql(mid+1,r,rson,a,b,val);
	return ql(mid+1,r,rson,a,b,ql(l,mid,lson,a,b,val));
}
ll qr(int l,int r,int x,int a,int b,ll val)
{
	if(a<=l&&r<=b)	return (val&r1[x])|((~val)&r0[x]);
	int mid=l+r>>1;
	if(b<=mid)	return qr(l,mid,lson,a,b,val);
	if(a>mid)	return qr(mid+1,r,rson,a,b,val);
	return qr(l,mid,lson,a,b,qr(mid+1,r,rson,a,b,val));
}
void dfs1(int x)
{
	siz[x]=1;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(to[i]!=fa[x])
		{
			fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];
			if(siz[to[i]]>siz[son[x]])	son[x]=to[i];
		}
	}
}
void dfs2(int x,int tp)
{
	top[x]=tp,p[x]=++p[0],q[p[0]]=x;
	if(son[x])	dfs2(son[x],tp);
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x]&&to[i]!=son[x])	dfs2(to[i],to[i]);
}
void ask(int x,int y,ll mx)
{
	ll ret=0,r0=0,r1=msk;
	st[0]=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]>dep[top[y]])	r0=qr(1,n,1,p[top[x]],p[x],r0),r1=qr(1,n,1,p[top[x]],p[x],r1),x=fa[top[x]];
		else	st[++st[0]]=y,y=fa[top[y]];
	}
	if(dep[x]>dep[y])	r0=qr(1,n,1,p[y],p[x],r0),r1=qr(1,n,1,p[y],p[x],r1);
	else	r0=ql(1,n,1,p[x],p[y],r0),r1=ql(1,n,1,p[x],p[y],r1);
	for(int i=st[0];i;i--)	y=st[i],r0=ql(1,n,1,p[top[y]],p[y],r0),r1=ql(1,n,1,p[top[y]],p[y],r1);
	for(int i=k-1;~i;i--)
	{
		if(mx<(1ULL<<i)||(r0&(1ULL<<i))>=(r1&(1ULL<<i)))	ret|=(r0&(1ULL<<i));
		else	ret|=(r1&(1ULL<<i)),mx-=(1ULL<<i);
	}
	printf("%llu\n",ret);
}
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
inline ll rd()
{
	ll ret=0;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	gc=getchar();
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc-‘0‘),gc=getchar();
	return ret;
}
int main()
{
	n=rd(),m=rd(),k=rd();
	int i,a,b,d;
	ll c;
	for(i=0;i<k;i++)	msk|=(1ULL<<i);
	for(i=1;i<=n;i++)	op[i]=rd(),v[i]=rd();
	memset(head,-1,sizeof(head));
	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
	dep[1]=1,dfs1(1),dfs2(1,1);
	build(1,n,1);
	for(i=1;i<=m;i++)
	{
		d=rd(),a=rd(),b=rd(),c=rd();
		if(d==1)	ask(a,b,c);
		else	updata(1,n,1,p[a],b,c);
	}
	return 0;
}//5 5 3 1 7 2 6 3 7 3 6 3 1 1 2 2 3 3 4 1 5 1 1 4 7 1 1 3 5 2 1 1 3 2 3 3 3 1 1 3 2 

【BZOJ4811】[Ynoi2017]由乃的OJ 樹鏈剖分+線段樹