Description
Input
Output
又是一道巧妙的题,被艾教拉上去没嘴出来的题。
最简单的我们会想到维护每一个区间每一位0进去与1进去出来的答案,最简单就是开64颗线段树来进行维护,可是这样内存占用太大,接着我们就会发现每一位直接其实是没有关系的,所以将64颗线段树合并成一个unsigned long long进行维护。
那么如何将两个区间合并呢,设左区间进1的答案为x1,进0的答案为x0,右区间进1的答案为y1,进0的答案为y0。
我们先考虑进左边区间是进入0,右边出1的情况。第一种情况是左边出1,此时需要右边继续出1,那么就是x0与y1共有1的部分,x0&y1了,第二种情况是左边出0,右边还需要出1,那么就是x0取反之后与y0的答案即为(~x0)&(y0),最后左边区间进0的答案就是两者一或了。
我们再考虑进左边区间是进入1,右边出1的情况。第一种情况是左边出1,此时需要右边继续出1,那么就是x1与y1共有1的部分,x1&y1了,第二种情况是左边出0,右边需要出1,那么就是x1取反之后与y0的答案即为(~x1)&(y0),最后左边区间进1的答案就是两者一或了。
在实现的时候我们又会发现从左进与从右进答案是不一样的,所以需要开两颗线段树,一颗合并从左到右,另一颗从右向左合并即可。
最后求解答案的时候,如果这一位答案能得到1,且加上它不超过要求大小,就贪心的选它作为答案的这一位,注意啦,要记得多加一个变量来存当前选择了的数字,因为有可能我选0出来的是1,答案和当前构成的数字并不一样哦。
下附AC代码
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
#define maxn 100005
using namespace std;
typedef unsigned long long ull;
inline ull read()
{
ull x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ull n,m,k;
struct nod
{
ull x1,x0;
nod(ull op,ull now)
{
if(op==1)
{
x0=(0ull&now);
x1=((~0ull)&now);
}
if(op==2)
{
x0=(0ull|now);
x1=((~0ull)|now);
}
if(op==3)
{
x0=(0ull^now);
x1=((~0ull)^now);
}
}
nod(){x1=~0ull;x0=0;}
};
nod operator + (nod a,nod b)
{
nod ans;
ans.x0=(a.x0&b.x1)|((~a.x0)&b.x0);
ans.x1=(a.x1&b.x1)|((~a.x1)&b.x0);
return ans;
}
nod datl[maxn<<2],datr[maxn<<2];
void pushup(ull now)
{
datl[now]=datl[lson]+datl[rson];
datr[now]=datr[rson]+datr[lson];
}
void update(ull ql,ull qr,ull op,ull add,ull nl,ull nr,ull now)
{
if(nl>nr)
return;
if(ql<=nl && nr<=qr)
{
datl[now]=datr[now]=nod(op,add);
return;
}
if(ql<=mid)
update(ql,qr,op,add,nl,mid,lson);
if(mid<qr)
update(ql,qr,op,add,mid+1,nr,rson);
pushup(now);
}
nod queryl(ull ql,ull qr,ull nl,ull nr,ull now)
{
if(nl>nr)
{
nod ans;
ans.x0=ans.x1=0ull;
return ans;
}
if(ql<=nl && nr<=qr)
{
return datl[now];
}
nod ans1,ans2;
ull flag1=0,flag2=0;
if(ql<=mid)
{
ans1=queryl(ql,qr,nl,mid,lson);
flag1=1;
}
if(mid<qr)
{
ans2=queryl(ql,qr,mid+1,nr,rson);
flag2=1;
}
if(flag1==1 && flag2==0) return ans1;
else if(flag1==0 && flag1==1) return ans2;
return ans1+ans2;
}
nod queryr(ull ql,ull qr,ull nl,ull nr,ull now)
{
if(nl>nr)
{
nod ans;
ans.x0=ans.x1=0ull;
return ans;
}
if(ql<=nl && nr<=qr)
{
return datr[now];
}
nod ans1,ans2;
ull flag1=0,flag2=0;
if(ql<=mid)
{
ans1=queryr(ql,qr,nl,mid,lson);
flag1=1;
}
if(mid<qr)
{
ans2=queryr(ql,qr,mid+1,nr,rson);
flag2=1;
}
if(flag1==1 && flag2==0) return ans1;
else if(flag1==0 && flag1==1) return ans2;
return ans2+ans1;
}
ull cnt;
ull o[maxn],a[maxn];
ull dfn[maxn];
ull fa[maxn],anc[maxn],siz[maxn],dep[maxn];
vector<ull>edge[maxn];
void dfs1(ull now,ull pa)
{
ull len=edge[now].size();
siz[now]=1;
fa[now]=pa;
for(ull i=0;i<len;i++)
{
ull nex=edge[now][i];
if(nex!=pa)
{
dep[nex]=dep[now]+1;
dfs1(nex,now);
siz[now]+=siz[nex];
}
}
}
void dfs2(ull now,ull top)
{
dfn[now]=++cnt;
anc[now]=top;
ull len=edge[now].size();
ull son=0;
for(ull i=0;i<len;i++)
{
ull nex=edge[now][i];
if(siz[nex]>siz[son] && nex!=fa[now])
{
son=nex;
}
}
if(son!=0)
dfs2(son,top);
for(ull i=0;i<len;i++)
{
ull nex=edge[now][i];
if(nex!=son && nex!=fa[now])
{
dfs2(nex,nex);
}
}
}
nod solve(ull p,ull q)
{
nod ans1,ans2;
while(anc[p]!=anc[q])
{
if(dep[anc[p]]>=dep[anc[q]])
{
ans1=ans1+queryr(dfn[anc[p]],dfn[p],1,n,1);
p=fa[anc[p]];
}
else
{
ans2=queryl(dfn[anc[q]],dfn[q],1,n,1)+ans2;
q=fa[anc[q]];
}
}
if(dep[p]>dep[q])
return ans1+queryr(dfn[q],dfn[p],1,n,1)+ans2;
else
return ans1+queryl(dfn[p],dfn[q],1,n,1)+ans2;
}
int main()
{
n=read();
m=read();
k=read();
for(ull i=1;i<=n;i++)
{
o[i]=read();
a[i]=read();
}
for(ull i=1;i<n;i++)
{
ull x,y;
x=read();
y=read();
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs1(1ull,0ull);
dfs2(1ull,1ull);
for(ull i=1ull;i<=n;i++)
{
update(dfn[i],dfn[i],o[i],a[i],1,n,1);
}
while(m--)
{
ull f=read(),x=read(),y=read();
ull z=read();
if(f==2ull)
{
update(dfn[x],dfn[x],y,z,1ull,n,1ull);
}
else
{
nod ans=solve(x,y);
ull res=0;
ull now=0;
for(ull i=k-1ull;i>=0;i--)
{
if(((ans.x0>>i)&1ull)==1ull)
{
res+=(1ull<<i);
}
else if((now+(1ull<<i))<=z && ((ans.x1>>i)&1ull)==1ull)
{
res+=(1ull<<i);
now+=(1ull<<i);
}
if(i==0)
break;
}
printf("%llu\n",res);
}
}
}