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]旅行——树链剖分+线段树(动态开点?)的更多相关文章
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- 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 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
随机推荐
- 设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇)
登录 保存密码 安全 加密 最近发现群内大伙对用Hbuilder做的APP怎么做登录功能以及维护登录状态非常困惑,而我前一段时间正好稍微研究了一下,所以把我知道的告诉大家,节约大家查找资料的时间. 你 ...
- idea下spring boot jpa写原生sql的时候,报Cannot resolve table错误
错误如图 打开View→Tool Windows→Persistence选项 在弹出的Persistence窗口的项目上右键,选择Generate Persistence Mapping→By Dat ...
- dotnetcore 与 hbase 之三——c# for hbase 客户端的使用
说明 在上一篇文章dotnetcore 与 hbase 之二--thrift 客户端的制作中已经可以找到 c# hbase 客户端的使用方法了,为什么这里单独列出一篇文章来讲述呢?最简单的理由就是,本 ...
- Python之(matplotlib、numpy、pandas)数据分析
一.Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形. 它主要用来回事图形,用来展现一些数据,更加直观的展示,让你第一眼就只要数 ...
- C#委托,匿名方法,Lambda,泛型委托,表达式树代码示例
第一分钟:委托 有些教材,博客说到委托都会提到事件,虽然事件是委托的一个实例,但是为了理解起来更简单,今天只谈委托不谈事件.先上一段代码: 下边的代码,完成了一个委托应用的演示.一个委托分三个步骤: ...
- linux 基础指令
df -h 查看磁盘空间 root@ubuntu:/etc# df -h Filesystem Size Used Avail Use% Mounted on udev 970M 0 970M 0% ...
- Java调用Python相关问题:指定python环境、传入参数、返回结果
本篇文章涉及到的操作均在Windows系统下进行,Java调用python在原理上不难,但是可能在实际应用中会有各种各样的需求,网上其他的资料很不全,所以又总结了这篇文章,以供参考. 一.指定pyth ...
- python 复制列表
python的变量仅仅是指向对象的标签,所以在操作列表的时候,list1 = list2这种做法只会复制一个标签,然后指向对象,并非生成一个新的对象. 大致有5中方法可以复制列表: a = [1,2, ...
- Centos7.x固定网络IP配置
1.管理员帐号密码登录centos系统 2. cd/etc/sysconfig/network-script/ 3. ls查看 4.vi 编辑 ifcfg-ens33(不同服务器网卡名 ...
- awk初级教程
参考:sed & awk 概述 sed & awk指令组成 与sed区别 尽管awk指令与sed指令的结构相同,都由模式和过程两部分组成,但过程本身有很大不同. awk看上去不像编辑器 ...