睡觉困难综合症
题目描述
由乃这个问题越想越迷糊,已经达到了废寝忘食的地步。结果她发现……晚上睡不着了!只能把自己的一个神经元(我们可以抽象成一个树形结构)拿出来,交给Deus。
这个神经元是一个有 个点的树,每个点的包括一个位运算 和一个权值 ,位运算有&,l,^三种,分别用1,2,3表示。
为了治疗失眠,Deus可以将一些神经递质放在点 上,初始的刺激值是 。
然后 依次经过从 到 的所有节点,每经过一个点 , 就变成 ,所以他想问你,最后到 时,希望得到的刺激值尽可能大,所以最大值的 可以是多少呢?当然由于初始的神经递质的量有限,所以给定的初始值 必须是在 之间。Deus每次都会给你3个数, , , 。
不过,Deus为了提升治疗效果,可能会对一些神经节点进行微调。在这种情况下,也会给三个数 , , ,意思是把 点的操作修改为 ,数值改为
输入格式:
第一行三个数 , , 。 的意义是每个点上的数,以及询问中的数值 都 < 。
之后 行,每行两个数 , 表示该点的位运算编号以及数值
之后 - 1行,每行两个数 , 表示 和 之间有边相连
之后 行,每行四个数, , , , 表示这次操作为 (1位询问,2为更改), , , 意义如题所述
输出格式:
对于每个操作1,输出到最后可以造成的最大刺激度
看不懂可以传送到洛谷去。
解:
如题,这个是NOI某年T1的加强版。如果没有做过起床困难综合症,建议先去做一下那道,虽然蒟蒻的我并没有做~
最近刷树剖板子似乎稍微熟练了那么一点。
似乎可以用LCT,时间复杂度更优秀,但是我不会啊!!!!!
那我们就树剖吧(惊人码量)。
为什么要来做这道题?最近听到高二的学长讲线段树维护位运算的姿势,想来练一练,正好选到这道题了。
还是使用原来题目的思想,用全1跑一遍全0跑一遍,看看对应位置会变成什么,然后贪心。
如何维护链上信息,同样树剖,使用线段树维护经过一段区间操作全1会变成什么全0会变成什么。
由于不知道树链的方向,我们还要维护从上到下和从下到上。也就是说,线段树上要维护4个值。
写的时候,线段树没开够,左移没打1LL,维护从上到下和从下到上搞反了。这个故事告诉我们不要在午休之前写代码。
还是贴波代码吧(树剖现在日常6KB了,是不是我姿势不够高超?):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
struct lxy{
int to,next;
}eg[200005];
struct segment_tree{
int lson,rson,l,r;
unsigned long long upone,upzero,done,dzero;
}b[200005];
struct barg{
unsigned long long zero,one;
}hhh;
int fa[100005],tp[100005],size[100005],wson[100005];
int opt[100005],bl[100005],dep[100005],head[100005];
bool vis[100005];
unsigned long long v[100005],inf;
int n,m,k,cnt,root;
void build(int &u,int l,int r)
{
u=++cnt;
b[u].l=l,b[u].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(b[u].lson,l,mid);
build(b[u].rson,mid+1,r);
}
void update(int u)
{
b[u].dzero=((b[b[u].lson].dzero&b[b[u].rson].done)|((~b[b[u].lson].dzero)&b[b[u].rson].dzero));
b[u].done=((b[b[u].lson].done&b[b[u].rson].done)|((~b[b[u].lson].done)&b[b[u].rson].dzero));
b[u].upzero=((b[b[u].rson].upzero&b[b[u].lson].upone)|((~b[b[u].rson].upzero)&b[b[u].lson].upzero));
b[u].upone=((b[b[u].rson].upone&b[b[u].lson].upone)|((~b[b[u].rson].upone)&b[b[u].lson].upzero));
return;
}
void modify(int u,int pos,int opti,unsigned long long vi)
{
if(b[u].l==b[u].r)
{
if(opti==1)
{
b[u].upone=vi,b[u].upzero=0;
b[u].done=vi,b[u].dzero=0;
}
if(opti==2)
{
b[u].upone=inf,b[u].upzero=vi;
b[u].done=inf,b[u].dzero=vi;
}
if(opti==3)
{
b[u].upone=(inf^vi),b[u].upzero=vi;
b[u].done=(inf^vi),b[u].dzero=vi;
}
return;
}
int mid=(b[u].l+b[u].r)>>1;
if(pos<=mid) modify(b[u].lson,pos,opti,vi);
else modify(b[u].rson,pos,opti,vi);
update(u);
}
barg query(int u,int l,int r,bool type)
{
if(b[u].l==l&&b[u].r==r)
{
if(type==0){
hhh.zero=b[u].upzero;
hhh.one=b[u].upone;
}
if(type==1){
hhh.zero=b[u].dzero;
hhh.one=b[u].done;
}
return hhh;
}
int mid=(b[u].l+b[u].r)>>1;
if(r<=mid) return query(b[u].lson,l,r,type);
else if(l>mid) return query(b[u].rson,l,r,type);
barg lll=query(b[u].lson,l,mid,type);
barg rrr=query(b[u].rson,mid+1,r,type);
if(type==1){
hhh.zero=((lll.zero&rrr.one)|((~lll.zero)&rrr.zero));//这个转移还是比较巧妙吧
hhh.one=((lll.one&rrr.one)|((~lll.one)&rrr.zero));
}
else{
hhh.zero=((rrr.zero&lll.one)|((~rrr.zero)&lll.zero));
hhh.one=((rrr.one&lll.one)|((~rrr.one)&lll.zero));
}
return hhh;
}
void add(int op,int ed)
{
eg[++cnt].next=head[op];
eg[cnt].to=ed;
head[op]=cnt;
}
void dfs1(int u,int dp)
{
dep[u]=dp;
vis[u]=1;
size[u]=1;
int w=0;
for(int i=head[u];i!=-1;i=eg[i].next)
if(vis[eg[i].to]==0)
{
fa[eg[i].to]=u;
dfs1(eg[i].to,dp+1);
size[u]+=size[eg[i].to];
if(size[eg[i].to]>w)
w=size[eg[i].to],wson[u]=eg[i].to;
}
vis[u]=0;
}
void dfs2(int u,int las)
{
vis[u]=1;
tp[u]=las;
bl[u]=++cnt;
modify(root,cnt,opt[u],v[u]);
if(wson[u]!=0) dfs2(wson[u],las);
for(int i=head[u];i!=-1;i=eg[i].next)
if(vis[eg[i].to]==0&&eg[i].to!=wson[u])
dfs2(eg[i].to,eg[i].to);
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&k);
unsigned long long s=1;
for(int i=1;i<=k;i++)
inf=inf+s,s=s*2;
for(int i=1;i<=n;i++)
scanf("%d%llu",&opt[i],&v[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
cnt=0;build(root,1,n);
dfs1(1,1);cnt=0;dfs2(1,1);
for(int i=1;i<=m;i++)
{
int x,q1,q2;
unsigned long long q3;
scanf("%d",&x);
if(x==1)
{
scanf("%d%d%llu",&q1,&q2,&q3);
queue <unsigned long long> x0;
queue <unsigned long long> x1;
stack <unsigned long long> y0;
stack <unsigned long long> y1;
while(tp[q1]!=tp[q2])
{
if(dep[tp[q1]]>=dep[tp[q2]]){
hhh=query(root,bl[tp[q1]],bl[q1],0);
q1=fa[tp[q1]];
x0.push(hhh.zero);
x1.push(hhh.one);
}
else{
hhh=query(root,bl[tp[q2]],bl[q2],1);
q2=fa[tp[q2]];
y0.push(hhh.zero);
y1.push(hhh.one);
}
}
if(dep[q1]>=dep[q2])
{
hhh=query(root,bl[q2],bl[q1],0);
q1=q2;
x0.push(hhh.zero);
x1.push(hhh.one);
}
else
{
hhh=query(root,bl[q1],bl[q2],1);
q2=q1;
y0.push(hhh.zero);
y1.push(hhh.one);
}
unsigned long long a0=0,a1=inf;
while(!x0.empty())
{
a0=(((~a0)&x0.front())|(a0&x1.front()));
a1=(((~a1)&x0.front())|(a1&x1.front()));
x0.pop();x1.pop();
}
while(!y0.empty())
{
a0=(((~a0)&y0.top())|(a0&y1.top()));
a1=(((~a1)&y0.top())|(a1&y1.top()));
y0.pop();y1.pop();
}
unsigned long long p,ans=0,ret=0;
for(int j=k-1;j>=0;j--)
{
p=(1ll<<j);
if((a0&p)==p)
{
ret=(ret|p);
continue;
}
if((a1&p)==p&&(ans|p)<=q3)
{
ans=(ans|p);
ret=(ret|p);
continue;
}
}
printf("%llu\n",ret);
}
else
{
scanf("%d%d%llu",&q1,&q2,&q3);
modify(root,bl[q1],q2,q3);
}
}
}