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. Windows10无法远程连接

    1.在桌面计算机上,选择右键->属性.左侧任务列表中选择远程设置(如果桌面没有计算机图标,按键盘+R 输入 control system) 钩上允许 远程连接到此计算机 正常情况下,这样就可以在 ...

  2. Visual Web Developer 2012安裝教程

    1.打开网页链接http://www.w3school.com.cn/aspnet/mvc_intro.asp 点击Visual Web Developer 2012进行安装安装平台(WebPlatf ...

  3. Eclipse-错误集

    1.The origin server did not find a current representation for the target resource or is not willing ...

  4. java List<String>的初始化 的一个小问题

    今天在处理生成excel的时候用到了java的list,但是需要直接赋值固定的几个变量,如果先初始化然后add的方法: List<String> name = new ArrayList( ...

  5. thinkphp5自动生成文档/注释代码自动生成api文档

    composer require weiwei/api-doc dev-master 安装之后,readme 有详细的使用说明代码: 部分界面: gitbub:https://github.com/z ...

  6. Mysql之表的查询

    一.单表的查询 首先让我们先熟悉一下mysql语句在查询操作时执行的顺序: (1)from  (2) on  (3) join  (4) where  (5)group by  (6) avg,sum ...

  7. JSON【1】

    http://repo1.maven.org/maven2/com/fasterxml/jackson/core/    JSON[jar]包下载 JSON是什么? 是一种轻量级的数据交换格式,完全独 ...

  8. Tensorflow&CNN:裂纹分类

    版权声明:本文为博主原创文章,转载 请注明出处:https://blog.csdn.net/sc2079/article/details/90478551 - 写在前面 本科毕业设计终于告一段落了.特 ...

  9. JAVA设计模式之单例模式(单件模式)—Singleton Pattern

    1.什么是单例模式? <Head First 设计模式>中给出如下定义:确保一个类只有一个实例,并提供一个全局访问点. 关键词:唯一实例对象. 2.单例模式的实现方式: 2.1 懒汉式 对 ...

  10. MySQL 主从复制 详细实例讲解 与 常见错误解决方法

    一.主机ip 192.168.0.128 ,从机ip:192.168.0.130 分别测试是否能ping通对方,如果不能,请关闭防火墙或开放对应端口 二.主服务器配置 1.备份主服务器的数据 mysq ...