P3313 [SDOI2014]旅行

一棵树,其中的点分类,点有权值,在一条链上找到一类点中的最大值或总和;

树链剖分把树变成链;

把每个宗教单开一个线段树,维护区间总和和最大值;

宗教很多,需要动态开点;

树链剖分:

void dfs1(int x,int fa)
{
siz[x]=;
father[x]=fa;
dep[x]=dep[fa]+;
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==fa) continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]]) son[x]=v;
}
} void dfs2(int x,int tp)
{
id[x]=++cnt;
top[x]=tp;
if(!son[x]) return ;
dfs2(son[x],tp);
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==father[x]||v==son[x]) continue;
dfs2(v,v);
}
} dfs1(,);
dfs2(,);

然后我们将每个点扔进所属宗教的线段树里;

设c[i]为i所属宗教,root[i]为线段树的总结点(根节点),注意这里用的节点为树链剖分后的新id

线段树不必记录自己的区间大小,节点是根据当前插入节点的新id决定的,不必将所有节点都开全,因为区间里的节点不都属于此线段树;

void build(int &rt,int l,int r,int w,int pos)
{
if(!rt) rt=++num;
//t[rt].l=l;t[rt].r=r;
t[rt].ma=max(t[rt].ma,w);
t[rt].sum+=w;
if(l==r) return ;
int mid=(l+r)>>;
if(pos<=mid) build(t[rt].l,l,mid,w,pos);
else build(t[rt].r,mid+,r,w,pos);
} for(int i=;i<=n;i++)
{
build(root[c[i]],,n,w[i],id[i]);
}

宗教会变,我们需要删除操作和插入操作;

删除时将他所在线段树中的节点删掉即可,插入即为建树操作;

点权值会变,我们只要把点删去,再将他作为一个新点插入即可;

求和操作:

正规树链剖分操作,将链上区间线段树求和即可,注意调用相关的线段树;

求最大值同上;

int query_tot(int rt,int lb,int rb,int l,int r)
{
if(r<lb||l>rb) return ;
if(r>=rb&&l<=lb) return t[rt].sum;
int mid=(lb+rb)>>;
return query_tot(t[rt].l,lb,mid,l,r)+query_tot(t[rt].r,mid+,rb,l,r);
} int tree_tot(int x,int y,int c)
{
int ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query_tot(root[c],,n,id[top[x]],id[x]);
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query_tot(root[c],,n,id[x],id[y]);
return ans;
} int query_ma(int rt,int lb,int rb,int l,int r)
{
if(r<lb||l>rb) return ;
if(r>=rb&&l<=lb) return t[rt].ma;
int mid=(lb+rb)>>;
return max(query_ma(t[rt].l,lb,mid,l,r),query_ma(t[rt].r,mid+,rb,l,r));
} int tree_ma(int x,int y,int c)
{
int ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,query_ma(root[c],,n,id[top[x]],id[x]));
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,query_ma(root[c],,n,id[x],id[y]));
return ans;
}

总代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+;
int pre[maxn*],last[maxn],other[maxn*],l;
int w[maxn],c[maxn]; struct node_sec
{
int l,r,ma,sum;
}t[maxn*]; void add(int x,int y)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
} int n,m;
int father[maxn];
int siz[maxn],son[maxn];
int dep[maxn];
void dfs1(int x,int fa)
{
siz[x]=;
father[x]=fa;
dep[x]=dep[fa]+;
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==fa) continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>siz[son[x]]) son[x]=v;
}
}
int cnt,id[maxn],top[maxn]; void dfs2(int x,int tp)
{
id[x]=++cnt;
top[x]=tp;
if(!son[x]) return ;
dfs2(son[x],tp);
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==father[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int root[maxn];
int num;
void build(int &rt,int l,int r,int w,int pos)
{
if(!rt) rt=++num;
//t[rt].l=l;t[rt].r=r;
t[rt].ma=max(t[rt].ma,w);
t[rt].sum+=w;
if(l==r) return ;
int mid=(l+r)>>;
if(pos<=mid) build(t[rt].l,l,mid,w,pos);
else build(t[rt].r,mid+,r,w,pos);
}
char s[]; void tree_remove(int &rt,int l,int r,int pos)
{
if(l==r)
{
t[rt].ma=;t[rt].sum=;
return ;
}
int mid=(l+r)>>;
if(pos<=mid) tree_remove(t[rt].l,l,mid,pos);
else tree_remove(t[rt].r,mid+,r,pos);
t[rt].ma=max(t[t[rt].l].ma,t[t[rt].r].ma);
t[rt].sum=t[t[rt].l].sum+t[t[rt].r].sum;
} int query_tot(int rt,int lb,int rb,int l,int r)
{
if(r<lb||l>rb) return ;
if(r>=rb&&l<=lb) return t[rt].sum;
int mid=(lb+rb)>>;
return query_tot(t[rt].l,lb,mid,l,r)+query_tot(t[rt].r,mid+,rb,l,r);
} int tree_tot(int x,int y,int c)
{
int ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query_tot(root[c],,n,id[top[x]],id[x]);
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query_tot(root[c],,n,id[x],id[y]);
return ans;
} int query_ma(int rt,int lb,int rb,int l,int r)
{
if(r<lb||l>rb) return ;
if(r>=rb&&l<=lb) return t[rt].ma;
int mid=(lb+rb)>>;
return max(query_ma(t[rt].l,lb,mid,l,r),query_ma(t[rt].r,mid+,rb,l,r));
} int tree_ma(int x,int y,int c)
{
int ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,query_ma(root[c],,n,id[top[x]],id[x]));
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,query_ma(root[c],,n,id[x],id[y]));
return ans;
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%d%d",&w[i],&c[i]);
}
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs1(,);
dfs2(,);
for(int i=;i<=n;i++)
{
build(root[c[i]],,n,w[i],id[i]);
}
for(int i=;i<=m;i++)
{
int x,y;
scanf("%s",s);
if(s[]=='C')
{
scanf("%d%d",&x,&y);
tree_remove(root[c[x]],,n,id[x]);
build(root[y],,n,w[x],id[x]);
c[x]=y;
continue;
}
else if(s[]=='W')
{
scanf("%d%d",&x,&y);
tree_remove(root[c[x]],,n,id[x]);
build(root[c[x]],,n,y,id[x]);
w[x]=y;
continue;
}
else if(s[]=='S')
{
scanf("%d%d",&x,&y);
printf("%d\n",tree_tot(x,y,c[x]));
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",tree_ma(x,y,c[x]));
}
} return ;
}

P3313 [SDOI2014]旅行——树链剖分+线段树(动态开点?)的更多相关文章

  1. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  2. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  5. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  6. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  7. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  8. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  10. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

随机推荐

  1. 音视频入门-09-RGB&YUV互转-使用开源库

    * 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...

  2. 在论坛中出现的比较难的sql问题:34(递归 获取连续值问题)

    原文:在论坛中出现的比较难的sql问题:34(递归 获取连续值问题) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.

  3. 2019年全国高校sql数据库

    2019年全国高校名单sql数据库信息: 根据教育部发布的文件整理形成可用.sql文件,导入数据库即可使用. 包括全国高等学校共计2956所,其中:普通高等学校2688所(含独立学院257所),成人高 ...

  4. 如何将SolidWorks文件另存为.obj文件及如何打开.obj格式文件

    原网站:http://fans.solidworks.com.cn/forum.php?mod=viewthread&tid=40238) OBJ文件是Alias Wavefront公司为它的 ...

  5. laravel 中将一对多关联查询的结果去重处理

    先交代下数据表结构 主表(订单表)order数据 ord_id order_sn 1 EX2019100123458 其中主键为order_id(订单id) 子表(门票表)order_item数据 o ...

  6. shell 脚本总结

    一.SHELL脚本是什么?它是必需的吗? 一个SHELL脚本就是一个文本文件,它包含一个或多个命令.系统管理员会经常需要使用多个命令来完成一项任务,此时可以添加这些所有命令在一个文本文件(SHELL脚 ...

  7. win10 下的 CUDA10.0 +CUDNN + tensorflow + opencv 环境部署

    1 CUDA 10.0 安装  win10 下的cuda 安装是非常简单的,和其他程序安装没什么区别,现在 tensorflow 1.13 版本以上 支持 CUDA 10.0 ,这里选取了CUDA 1 ...

  8. Vue指令之`v-text`和`v-html`

    v-text: 没有加载闪烁问题,它会覆盖元素中原本的内容,但是插值表达式,只会替换自己的这个占位符,不会把 整个元素的内容清空. v-html: 使用v-html可以把标签元素也能显示在元素上 &l ...

  9. 【SpringMVC】统一异常处理

    一.需求 二.统一异常处理解决方案 2.1 定义异常 2.2 异常处理 2.3 配置统一异常处理器 2.4 异常处理逻辑 一.需求 一般项目中都需要作异常处理,基于系统架构的设计考虑,使用统一的异常处 ...

  10. 分布式Hadoop和HBase整合

    环境: CentOS 6.6                hadoop-2.6.0            hbase-0.98.10.1 HBase1    192.168.1.4     Mast ...