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. 用ASP.NET Web API技术开发HTTP接口(一)

    开发工具 Visual Studio 2013 SQL Server 2008 R2 准备工作 启动Visual Studio 2013,新建一个ASP.NET Web应用程序,命名为SimpleAP ...

  2. vue 百度云上传文件PostObject

    百度云上传文件 API(PostObject) PostObject接口  : 接口描述 此接口使用HTML表单上传文件到指定bucket,用于实现通过浏览器上传文件到bucket.在PutObjec ...

  3. Pyhton模块和包

    一 模块 1.1 什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用pytho ...

  4. BeautifulSoup库的安装与使用

    BeautifulSoup库的安装 Win平台:“以管理员身份运行” cmd 执行 pip install beautifulsoup4 演示HTML页面地址:http://python123.io/ ...

  5. js展开循环

    当要对一个大数组进行循环时,通常会通过局部变量缓存数组长度来提高性能,例: for(var i=0,len=arr.len;i<len;i++){} 光是缓存数组长度或使用倒序遍历来减少判断外, ...

  6. BPM FlowPortal 开发环境及发布环境的配置

    开启开发模式 开发时应设置防缓存和调试信息输出. 开发后发布 开发完成后正式使用时,除了对以上各项做相反设置外,还需设置web.config中的JSVersion,使每个用户都能自动下载最新版的js文 ...

  7. MySQL常见问题集锦及注意事项

    一.表设计上的坑 1.字段设计 1.1 字段类型设计 尽量使用整型表示字符串: `INET_ATON(str)`,address to number `INET_NTOA(number)`,numbe ...

  8. L ==> E · L · K

    三剑客:Elastic Stack 在学习ELK前,先对 Lucene作基本了解. 今天才知道关系型数据库的索引是 B-Tree,罪过... 减少磁盘寻道次数 ---> 提高查询性能 Lucen ...

  9. SQL SERVER-LinkServer搬迁

    选中linkserver,按F7打开对象游览器, 选中linkserver,生成脚本. 把密码填入脚本运行即可 USE [master] GO /****** Object: LinkedServer ...

  10. Linux下Mysql服务安装【1】

    https://www.cnblogs.com/xiaxiaoxu/p/9978976.html 第一步:获取mysql8.0的yum源 进入mysql官网获取RPM包下载地址 https://dev ...