树链剖分模板题:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=50005;
int n,q;
int w[maxn];//每个点的权值
int father[maxn];//每个点的父亲
int son[maxn]; //每个点的重儿子是谁
int id[maxn];//使用线段树是的节点编号要用id[]存
int pre[maxn];//将重新编号的节点映射回来
int top[maxn];//每条树链的顶点
int deep[maxn];
int sz[maxn];//每个点的子树节点个数
struct Node{
int w;
int maxx;
}tree[4*maxn];
vector<int>vec[maxn];
void init(){
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
for(int i=1;i<=n;i++){
cin>>w[i];
}
}
void dfs1(int u,int fa,int depth){
father[u]=fa;
deep[u]=depth;
int max_son=-maxn;//记录重儿子个数
sz[u]=1;
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
if(v==fa)continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>max_son){
max_son=sz[v];
son[u]=v;
}
}
}
int tot=0;
void dfs2(int u,int tp){
top[u]=tp;
id[u]=++tot;//重新编号u (先自增后访问)
pre[tot]=u;//将编号映射回来
if(son[u])dfs2(son[u],tp);
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
if(v==father[u]||v==son[u])continue;
dfs2(v,v);
}
}
void build(int L,int R,int k){
if(L==R){
tree[k].w=w[pre[L]];
tree[k].maxx=w[pre[L]];
return;
}
int mid=(L+R)/2;
build(L,mid,2*k);
build(mid+1,R,2*k+1);
tree[k].w=tree[2*k].w+tree[2*k+1].w;
tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);
}
void update(int x,int t,int L,int R,int k){
if(L==R&&L==x){
tree[k].w=t;
tree[k].maxx=t;
return;
}
int mid=(L+R)/2;
if(x<=mid)
update(x,t,L,mid,2*k);
else
update(x,t,mid+1,R,2*k+1);
tree[k].w=tree[2*k].w+tree[2*k+1].w;
tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);
}
int query_max(int x,int y,int L,int R,int k){
int ans=-maxn;
if(R<=y&&L>=x){
return tree[k].maxx;
}
int mid=(L+R)/2;
if(x<=mid)
ans=max(ans,query_max(x,y,L,mid,2*k));
if(y>mid)
ans=max(ans,query_max(x,y,mid+1,R,2*k+1));
return ans;
}
int query_sum(int x,int y,int L,int R,int k){
int ans=0;
if(R<=y&&L>=x){
return tree[k].w;
}
int mid=(L+R)/2;
if(x<=mid)
ans+=query_sum(x,y,L,mid,2*k);
if(y>mid)
ans+=query_sum(x,y,mid+1,R,2*k+1);
return ans;
}
int QMAX(int u,int v){//查询点 u到点 v之间的最大值
int ans=-maxn;
while(top[u]!=top[v]){//若 u和 v在不同链上
if(deep[top[u]]>deep[top[v]])
swap(u,v);
ans=max(ans,query_max(id[top[v]],id[v],1,n,1));
v=father[top[v]];
}
if(deep[u]>deep[v])
swap(u,v);
ans=max(ans,query_max(id[u],id[v],1,n,1));
return ans;
}
int QSUM(int u,int v){
int ans=0;
while(top[u]!=top[v]){
if(deep[top[u]]>deep[top[v]])
swap(u,v);
ans+=query_sum(id[top[v]],id[v],1,n,1);
v=father[top[v]];
}
if(deep[u]>deep[v])
swap(u,v);
ans+=query_sum(id[u],id[v],1,n,1);
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
init();
int root=1;
dfs1(root,0,1);//根节点,father,深度
dfs2(root,root);//dfs2找树链
build(1,n,1);
cin>>q;
while(q--){
string s;
int u,v;
cin>>s>>u>>v;
if(s=="CHANGE")
update(id[u],v,1,n,1);//把点 u改成 v
else if(s=="QMAX")
cout<<QMAX(u,v)<<endl;
else
cout<<QSUM(u,v)<<endl;
}
return 0;
}
题意:有一棵n个点,n-1条边构成的树,点权要么为1,要么为0,现在支持以下三种操作:
1、把某个点及其子树点权值全部赋值成1
2、把某个点及其祖先点权值全部赋值为0
3、查询某个点的点权
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const ll MAXN = 1e18 + 7;
const int maxn = 500000 + 10;
vector<int>vec[maxn];
int deep[maxn];
int top[maxn];
int father[maxn];
int son[maxn];
int pre[maxn];
int id[maxn];
int sz[maxn];
int n;
void init() {
for (int i = 1; i<n; i++) {
int u, v;
cin >> u >> v;
vec[u].push_back(v);
vec[v].push_back(u);
}
}
void dfs1(int u, int fa, int dep) {
deep[u] = dep;
father[u] = fa;
sz[u] = 1;
int max_son = -maxn;
for (int i = 0; i<vec[u].size(); i++) {
int v = vec[u][i];
if (v == fa)continue;
dfs1(v, u, dep + 1);
sz[u] += sz[v];
if (max_son<sz[v]) {
max_son = sz[v];
son[u] = v;
}
}
}
int tot = 0;
void dfs2(int u, int tp) {
top[u] = tp;
id[u] = ++tot;
pre[tot] = u;
if (son[u])dfs2(son[u], tp);
for (int i = 0; i<vec[u].size(); i++) {
int v = vec[u][i];
if (v == father[u] || v == son[u])continue;
dfs2(v, v);
}
}
struct Node {
int w;
int lazy;
}tree[4 * maxn];
void pushdown(int k) {
if (tree[k].lazy != -1) {
tree[k<<1].lazy = tree[k << 1|1].lazy = tree[k].lazy;
tree[k << 1].w = tree[k << 1| 1].w = tree[k].lazy;
tree[k].lazy = -1;
}
}
void build(int L, int R, int k) {
tree[k].lazy = -1;//标记应该随时下放
if (L == R) {
return;
}
int mid = (L + R) / 2;
build(L, mid, 2 * k);
build(mid + 1, R, 2 * k + 1);
}
void update_tree(int L, int R, int k, int x, int y, int ww) {
if (x <= L&&y >= R) {
tree[k].w = ww;
tree[k].lazy = ww;
return;
}
pushdown(k);
int mid = (L + R) / 2;
if (x <= mid)
update_tree(L, mid, 2 * k, x, y, ww);
if (y>mid)
update_tree(mid + 1, R, 2 * k + 1, x, y, ww);
}
int query_tree(int L, int R, int k, int x) {
if (L == R) {
return tree[k].w;
}
pushdown(k);
int mid = (L + R) / 2;
if (x <= mid)
return query_tree(L, mid, 2 * k, x);
else
return query_tree(mid + 1, R, 2 * k + 1, x);
}
void LCA(int u, int v) {//1是祖先
while (top[u] != top[v]) {
if (deep[top[u]]>deep[top[v]])
swap(u, v);
update_tree(1, n, 1, id[top[v]], id[v], 0);
v = father[top[v]];
}
if (deep[u]>deep[v])
swap(u, v);
update_tree(1, n, 1, id[u], id[v], 0);
}
int main()
{
ios::sync_with_stdio(false);
cin >> n;
init();
int root = 1;
dfs1(root, -1, 1);
dfs2(root, root);
build(1, n, 1);
int q;
cin >> q;
while (q--) {
int cnt, v;
cin >> cnt >> v;
if (cnt == 1)
update_tree(1, n, 1, id[v], id[v] + sz[v] - 1, 1);//某一子树的序号一定连续
else if (cnt == 2)
LCA(1, v);
else
cout << query_tree(1, n, 1, id[v]) << endl;
}
return 0;
}