您的位置:首页 > 其它

bzoj 4811: [Ynoi2017]由乃的OJ

2017-12-20 17:03 309 查看

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

      又是一道巧妙的题,被艾教拉上去没嘴出来的题。

      最简单的我们会想到维护每一个区间每一位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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: