生活随笔
收集整理的這篇文章主要介紹了
[bzoj 4811] 由乃的OJ(贪心 + 树链剖分)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前置技能:[Noi2014]起床困難綜合癥。
不難看出,這道題其實就是上一道題的加強版
在上一道題中,因為位運算時位與位之間互不干擾
所以從高位到低位枚舉初始值二進制上的每一位為0和為1時,經過n次計算后這一位的結果,貪心選取
在這題中,我們也可以用同樣的思路求取答案
因為有樹上路徑查詢,考慮樹鏈剖分,用線段樹維護每一位初始為0和1時,經過一個區間的計算變為多少
因為&、|、^ 運算都符合結合律,所以這樣做是可行的
問題是,&、|、^ 運算并不都滿足交換律,即每個區間從左到右計算和從右到左計算得到的結果是不同的
而在樹上從x走到y的途中,并不保證一定按dfn序從小到大的順序走
所以我們還要分別維護每個區間從左到右計算和從右到左計算的結果
另外,給每一位都開一顆線段樹顯然是不現實的,
考慮到 k<=64,我們使用狀壓,把所有位都壓到一起,存到一顆線段樹中(注意要開unsigned long long)
#include<bits/stdc++.h>
using namespace std
;
typedef unsigned long long ull
;
const int N
=100010;
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
;
}
struct Edge
{int u
,v
,nxt
;
}edge
[N
<<1];
int head
[N
],cnt
;
void addedge(int u
,int v
){edge
[++cnt
]=(Edge
){u
,v
,head
[u
]};head
[u
]=cnt
;edge
[++cnt
]=(Edge
){v
,u
,head
[v
]};head
[v
]=cnt
;
}
int n
,m
,k
;
int dep
[N
],son
[N
],sz
[N
],top
[N
],fa
[N
],tid
[N
],rnk
[N
],ind
;
void dfs1(int u
,int f
){fa
[u
]=f
;dep
[u
]=dep
[f
]+1;sz
[u
]=1;for(int i
=head
[u
];~i
;i
=edge
[i
].nxt
) if(edge
[i
].v
!=f
){dfs1(edge
[i
].v
,u
);if(sz
[edge
[i
].v
]>sz
[son
[u
]]) son
[u
]=edge
[i
].v
;sz
[u
]+=sz
[edge
[i
].v
];}
}
void dfs2(int u
,int tp
){top
[u
]=tp
;tid
[u
]=++ind
;rnk
[ind
]=u
;if(sz
[u
]>1) dfs2(son
[u
],tp
);for(int i
=head
[u
];~i
;i
=edge
[i
].nxt
) if(edge
[i
].v
!=son
[u
]&&edge
[i
].v
!=fa
[u
])dfs2(edge
[i
].v
,edge
[i
].v
);
}
ull tran
[N
<<3][2][2];
inline ull
transf(ull a
,ull b
,int opt
){if(opt
==1){return a
&b
;}else if(opt
==2){return a
|b
;}else return a
^b
;
}
int op
;
inline ull
transf(ull a
,ull b
){if(op
==1){return a
&b
;}else if(op
==2){return a
|b
;}else return a
^b
;
}
inline void pushup(int o
){int ls
=o
<<1,rs
=o
<<1|1;tran
[o
][1][0]=(tran
[ls
][1][0]&tran
[rs
][1][0])|(~tran
[ls
][1][0]&tran
[rs
][0][0]);tran
[o
][1][1]=(tran
[rs
][1][1]&tran
[ls
][1][1])|(~tran
[rs
][1][1]&tran
[ls
][0][1]);tran
[o
][0][0]=(tran
[ls
][0][0]&tran
[rs
][1][0])|(~tran
[ls
][0][0]&tran
[rs
][0][0]);tran
[o
][0][1]=(tran
[rs
][0][1]&tran
[ls
][1][1])|(~tran
[rs
][0][1]&tran
[ls
][0][1]);
}
void update(int o
,int l
,int r
,int x
,ull k
){if(l
==r
){tran
[o
][0][0]=tran
[o
][0][1]=transf(0ull,k
);tran
[o
][1][0]=tran
[o
][1][1]=transf(~0ull,k
);}else{int mid
=l
+r
>>1;if(x
<=mid
) update(o
<<1,l
,mid
,x
,k
);else update(o
<<1|1,mid
+1,r
,x
,k
);pushup(o
); }
}
ull t1
[2],t0
[2];
int t
;
void query(int o
,int l
,int r
,int a
,int b
){if(a
<=l
&&b
>=r
){ if(!t
){ull tt
=t1
[t
];t1
[t
]=(tran
[o
][1][t
]&t1
[t
])|(~tran
[o
][1][t
]&t0
[t
]);t0
[t
]=(tran
[o
][0][t
]&tt
)|(~tran
[o
][0][t
]&t0
[t
]);}else{t1
[t
]=(t1
[t
]&tran
[o
][1][t
])|(~t1
[t
]&tran
[o
][0][t
]);t0
[t
]=(t0
[t
]&tran
[o
][1][t
])|(~t0
[t
]&tran
[o
][0][t
]); }}else{int mid
=l
+r
>>1;if(b
>mid
) query(o
<<1|1,mid
+1,r
,a
,b
);if(a
<=mid
) query(o
<<1,l
,mid
,a
,b
); }
}
ull val
[N
];
int opt
[N
];
void build(int o
,int l
,int r
){if(l
==r
){ tran
[o
][0][0]=tran
[o
][0][1]=transf(0ull,val
[rnk
[l
]],opt
[rnk
[l
]]);tran
[o
][1][0]=tran
[o
][1][1]=transf(~0ull,val
[rnk
[l
]],opt
[rnk
[l
]]);}else{int mid
=l
+r
>>1;build(o
<<1,l
,mid
);build(o
<<1|1,mid
+1,r
);pushup(o
);}
}
ull z
;
inline ull
ask(int x
,int y
){t0
[0]=t0
[1]=0;t1
[0]=t1
[1]=~0ull;while(top
[x
]!=top
[y
]){if(dep
[top
[x
]]>dep
[top
[y
]]){t
=1;query(1,1,n
,tid
[top
[x
]],tid
[x
]);x
=fa
[top
[x
]];}else{t
=0;query(1,1,n
,tid
[top
[y
]],tid
[y
]);y
=fa
[top
[y
]];}}if(dep
[x
]>dep
[y
]){t
=1;query(1,1,n
,tid
[y
],tid
[x
]); }else{t
=0;query(1,1,n
,tid
[x
],tid
[y
]);}ull T0
=(t0
[1]&t1
[0])|(~t0
[1]&t0
[0]);ull T1
=(t1
[1]&t1
[0])|(~t1
[1]&t0
[0]);ull v
=0,ans
=0;for(int i
=k
;~i
;i
--){ull v1
=v
|(1ull<<i
);if(v1
<=z
){if(T0
&(1ull<<i
)||!(T1
&(1ull<<i
)))ans
|=T0
&(1ull<<i
);else{ans
|=T1
&(1ull<<i
);v
|=(1ull<<i
);}}else{ans
|=T0
&(1ull<<i
);}}return ans
;
}
int main(){memset(head
,cnt
=-1,sizeof(head
));n
=read();m
=read();k
=read();k
--;for(int i
=1;i
<=n
;i
++)opt
[i
]=read(),val
[i
]=read();for(int i
=1;i
<n
;i
++)addedge(read(),read());dfs1(1,1);dfs2(1,1);build(1,1,n
);while(m
--){int q
=read(),x
=read( ),y
=read( );z
=read( );if(q
==1) printf("%llu\n",ask(x
,y
));else{op
=y
;update(1,1,n
,tid
[x
],z
);}}return 0;
}
總結
以上是生活随笔為你收集整理的[bzoj 4811] 由乃的OJ(贪心 + 树链剖分)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。