[DS记录]P5354 [Ynoi2017] 由乃的 OJ
command_block
2021-06-28 18:23:17
**题意** : 给出一棵 $n$ 个点的树,每个点的包括一个位运算 $opt$ 和一个权值 $x$,位运算有`&`,`|`,`^` 三种。
每次询问包含三个整数 $x,y,z$ ,初始选定一个数 $v$ 。
然后 $v$ 依次经过从 $x$ 到 $y$ 的所有节点,每经过一个点 $i$,$v$ 就变成 $v\ opt_i\ x_i$,所以他想问你,最后到 $y$ 时,希望得到的值尽可能大,求最大值。
给定的初始值 $v$ 必须是在 $[0,z]$ 之间。
每次修改包含三个整数 $x,y,z$,意思是把 $x$ 点的操作修改为 $y$,数值改为 $z$。
$n,m\leq 10^5,w<2^{64}$ ,时限$\texttt{0.25s}$。
------------
位运算的每一位是独立的,只需要得到每一位的真值表,然后按位贪心。
用树剖维护,合并真值表时用位运算优化,复杂度 $O\big((n+m)(\log^2n+w)\big)$。实际常数很小,可以通过。
```cpp
#include<algorithm>
#include<cstdio>
#include<vector>
#define pb push_back
#define ull unsigned long long
#define MaxN 100500
using namespace std;
vector<int> g[MaxN];
struct TNode{int p,f,tf;}b[MaxN];
int siz[MaxN],dep[MaxN];
void pfs1(int u)
{
siz[u]=1;
for (int i=0,v;i<g[u].size();i++)
if (!siz[v=g[u][i]]){
dep[v]=dep[b[v].f=u]+1;
pfs1(v);
siz[u]+=siz[v];
if (siz[v]>siz[b[u].p])
b[u].p=v;
}
}
int dfn[MaxN],tp[MaxN],tim;
void pfs2(int u,int tf)
{
tp[dfn[u]=++tim]=u;
b[u].tf=tf;
if (b[u].p)pfs2(b[u].p,tf);
for (int i=0;i<g[u].size();i++)
if (!b[g[u][i]].tf)
pfs2(g[u][i],g[u][i]);
}
const ull Bas=18446744073709551615ull;
struct TT{ull s0,s1;}a[MaxN<<2][2],I=(TT){0,Bas};
TT operator + (const TT &A,const TT &B)
{return (TT){(A.s0&B.s1)|((Bas^A.s0)&B.s0),(A.s1&B.s1)|((Bas^A.s1)&B.s0)};}
inline void up(int u){
a[u][0]=a[u<<1][0]+a[u<<1|1][0];
a[u][1]=a[u<<1|1][1]+a[u<<1][1];
}
void Init(int op,ull x,TT *a){
if (op==1)a[0]=a[1]=(TT){0,x};
if (op==2)a[0]=a[1]=(TT){x,Bas};
if (op==3)a[0]=a[1]=(TT){x,Bas^x};
}
int n,opt[MaxN];ull sx[MaxN];
void build(int l=1,int r=n,int u=1)
{
if (l==r){Init(opt[tp[l]],sx[tp[l]],a[u]);return ;}
int mid=(l+r)>>1;
build(l,mid,u<<1);
build(mid+1,r,u<<1|1);
up(u);
}
int to,wfop;ull wfc;
void chg(int l=1,int r=n,int u=1)
{
if (l==r){Init(wfop,wfc,a[u]);return ;}
int mid=(l+r)>>1;
if (to<=mid)chg(l,mid,u<<1);
else chg(mid+1,r,u<<1|1);
up(u);
}
int wfl,wfr;TT _R,R;
void qry(int l=1,int r=n,int u=1)
{
if (wfl<=l&&r<=wfr){
_R=wfop ? a[u][1]+_R : _R+a[u][0];
return ;
}int mid=(l+r)>>1;
if (wfl<=mid)qry(l,mid,u<<1);
if (mid<wfr)qry(mid+1,r,u<<1|1);
}
int lca(int u,int v)
{
while(b[u].tf!=b[v].tf){
if (dep[b[u].tf]<dep[b[v].tf])swap(u,v);
u=b[b[u].tf].f;
}return dep[u]<dep[v] ? u : v;
}
void pqry(int u,int lim)
{
if (dep[u]<lim)return ;
while(lim<dep[b[u].tf]){
wfl=dfn[b[u].tf];wfr=dfn[u];
_R=I;qry();R=wfop ? R+_R : _R+R;
u=b[b[u].tf].f;
}wfl=dfn[u]-dep[u]+lim;wfr=dfn[u];
_R=I;qry();R=wfop ? R+_R : _R+R;
}
int m;
int main()
{
scanf("%d%d%*d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d%llu",&opt[i],&sx[i]);
for (int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
g[u].pb(v);g[v].pb(u);
}dep[1]=1;pfs1(1);pfs2(1,1);
build();
for (int i=1,op,x,y;i<=m;i++){
ull z;
scanf("%d%d%d%llu",&op,&x,&y,&z);
if (op==2){to=dfn[x];wfop=y;wfc=z;chg();}
else {
int t=lca(x,y);
R=I;
wfop=1;pqry(x,dep[t]+1);
TT sav=R;R=I;
wfop=0;pqry(y,dep[t]);
R=sav+R;
ull ans=0,buf=0;
for (int i=63;i>=0;i--){
bool f0=R.s0>>i&1,f1=R.s1>>i&1;
if (f0)ans|=1ull<<i;
else if (f1&&(buf|(1ull<<i))<=z)
{ans|=1ull<<i;buf|=1ull<<i;}
}printf("%llu\n",ans);
}
}return 0;
}
```