题目链接

无优化版本(170行):

/*
首先树剖可以维护树上的链Sum、Max
可以对每个宗教建一棵线段树,那这题就很好做了
不过10^5需要动态开点 (不明白为什么nlogn不需要回收就可以 不是每个Insert加log个节点?)
操作修改完更改原数列!盲人。。
*/
#include<cstdio>
#include<cctype>
#include<algorithm>
#define gc() getchar()
#define now node[rt]
#define lson node[rt].ls
#define rson node[rt].rs
const int N=1e5+5,MAXN=N*19; int n,q,cnt,H[N],Enum,to[N<<1],nxt[N<<1],fa[N],dep[N],id[N],son[N],sz[N],top[N];
int idx,pos[N],W[N],rel[N],root[N],pool[MAXN];
struct Seg_Tree
{
struct Node
{
int sum,maxn,ls,rs,l,r;
inline void Init() {sum=maxn=l=r=ls=rs=0;}
}node[MAXN];
inline int new_Node() {return pool[++idx];}
inline void del_Node(int rt) {now.Init(), pool[idx--]=rt;}
inline void PushUp(int rt)
{
now.sum = node[lson].sum + node[rson].sum,
now.maxn= std::max(node[lson].maxn, node[rson].maxn);
}
void Insert(int l,int r,int &rt,int x)
{
if(!rt) rt=new_Node(), now.l=l, now.r=r;
if(l==r) now.sum=now.maxn=W[x];
else
{
int m=l+r>>1;
if(id[x]<=m) /*lson?0:lson=new_Node(),*/ Insert(l,m,lson,x);//不想打括号--
else /*rson?0:rson=new_Node(),*/ Insert(m+1,r,rson,x);
PushUp(rt);
}
}
void Delete(int rt,int x,int &son)//可以用Insert将其值变为0来删除 但是就不能重复利用了
{
if(now.l==now.r) son=0, del_Node(rt);//父亲的这个儿子也要删!
else
{
int m=now.l+now.r>>1;
if(id[x]<=m) Delete(lson,x,lson);
else Delete(rson,x,rson);
if(now.sum==W[x]) del_Node(rt), son=0;
else PushUp(rt);
}
}
void Modify(int rt,int p,int v)
{
if(now.l==now.r) now.maxn=now.sum=v;
else
{
int m=now.l+now.r>>1;
if(p<=m) Modify(lson,p,v);
else Modify(rson,p,v);
PushUp(rt);
}
}
int Query_Max(int rt,int L,int R)
{
if(!rt) return 0;
if(L<=now.l && now.r<=R) return now.maxn;
int m=now.l+now.r>>1;
if(L<=m)
if(m<R) return std::max(Query_Max(lson,L,R),Query_Max(rson,L,R));
else return Query_Max(lson,L,R);
return Query_Max(rson,L,R);
}
int Query_Sum(int rt,int L,int R)
{
if(!rt) return 0;
if(L<=now.l && now.r<=R) return now.sum;
int m=now.l+now.r>>1;
if(L<=m)
if(m<R) return Query_Sum(lson,L,R)+Query_Sum(rson,L,R);
else return Query_Sum(lson,L,R);
return Query_Sum(rson,L,R);
}
}t;
#undef now
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline void AddEdge(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void DFS1(int x)
{
sz[x]=1; int mx=0;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
if(mx<sz[v]) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int tp)
{
id[x]=++cnt, top[x]=tp;
if(son[x])
{
DFS2(son[x],tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=fa[x] && to[i]!=son[x])
DFS2(to[i], to[i]);
}
}
void Query_Chain_Sum(int x,int y)
{
long long res=0;int rt=root[rel[x]];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
res += t.Query_Sum(rt,id[top[x]],id[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
res += t.Query_Sum(rt,id[x],id[y]);
printf("%lld\n",res);
}
void Query_Chain_Max(int x,int y)
{
int res=0, rt=root[rel[x]];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
res = std::max(res, t.Query_Max(rt,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
res = std::max(res, t.Query_Max(rt,id[x],id[y]));
printf("%d\n",res);
} int main()
{
#ifndef ONLINE_JUDGE
freopen("3531.in","r",stdin);
freopen("my.out","w",stdout);
#endif n=read(),q=read();
for(int i=1; i<MAXN; ++i) pool[i]=i;
for(int i=1; i<=n; ++i) W[i]=read(), rel[i]=read();
for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v);
DFS1(1), DFS2(1,1);
for(int i=1; i<=n; ++i) t.Insert(1,n,root[rel[i]],i);
char opt[5]; int x,y;
while(q--)
{
scanf("%s",opt), x=read(), y=read();
switch(opt[1])
{
case 'C': t.Delete(root[rel[x]],x,root[rel[x]]), rel[x]=y, t.Insert(1,n,root[y],x);
break;
case 'W': t.Modify(root[rel[x]],id[x],y), W[x]=y;//!
break;
case 'S': Query_Chain_Sum(x,y);
break;
case 'M': Query_Chain_Max(x,y);
break;
}
}
return 0;
}

优化(短多了):

//不知道为什么只需nlogn个节点 不需要回收
//+各种函数简化
#include<cstdio>
#include<cctype>
#include<algorithm>
#define gc() getchar()
#define now node[rt]
#define lson node[rt].ls
#define rson node[rt].rs
const int N=1e5+5,MAXN=N*19; int n,q,cnt,H[N],Enum,to[N<<1],nxt[N<<1],fa[N],dep[N],id[N],son[N],sz[N],top[N];
int idx,pos[N],W[N],rel[N],root[N],pool[MAXN];
struct Seg_Tree
{
struct Node
{
int sum,maxn,ls,rs;
inline void Init() {sum=maxn=ls=rs=0;}
}node[MAXN];
inline int new_Node() {return ++idx;}
// inline int new_Node() {return pool[++idx];}
// inline void del_Node(int rt) {now.Init(), pool[idx--]=rt;}
inline void PushUp(int rt)
{
now.sum = node[lson].sum + node[rson].sum,
now.maxn= std::max(node[lson].maxn, node[rson].maxn);
}
void Update(int l,int r,int &rt,int p,int v)
{
if(!rt) rt=new_Node();
if(l==r) now.sum=now.maxn=v;
else
{
int m=l+r>>1;
if(p<=m) Update(l,m,lson,p,v);
else Update(m+1,r,rson,p,v);
PushUp(rt);
}
}
int Query(int l,int r,int rt,int L,int R,bool opt)
{
if(!rt) return 0;
if(L<=l && r<=R) return opt?now.sum:now.maxn;
int m=l+r>>1;
if(L<=m)
if(m<R) return opt?Query(l,m,lson,L,R,opt)+Query(m+1,r,rson,L,R,opt)
:std::max(Query(l,m,lson,L,R,opt),Query(m+1,r,rson,L,R,opt));
else return Query(l,m,lson,L,R,opt);
return Query(m+1,r,rson,L,R,opt);
}
}t;
#undef now
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline void AddEdge(int u,int v)
{
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void DFS1(int x)
{
sz[x]=1; int mx=-1;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
if(mx<sz[v]) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int tp)
{
id[x]=++cnt, top[x]=tp;
if(son[x])
{
DFS2(son[x],tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=fa[x] && to[i]!=son[x])
DFS2(to[i], to[i]);
}
}
void Query_Chain(int x,int y,bool opt)
{
int res=0;int rt=root[rel[x]];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
if(opt) res += t.Query(1,n,rt,id[top[x]],id[x],1);
else res = std::max(res, t.Query(1,n,rt,id[top[x]],id[x],0));
x=fa[top[x]];
}
if(id[x]>id[y]) std::swap(x,y);
if(opt) res += t.Query(1,n,rt,id[x],id[y],1);
else res = std::max(res, t.Query(1,n,rt,id[x],id[y],0));
printf("%d\n",res);
} int main()
{
#ifndef ONLINE_JUDGE
freopen("35312.in","r",stdin);
freopen("my.out","w",stdout);
#endif n=read(),q=read();
for(int i=1; i<MAXN; ++i) pool[i]=i;
for(int i=1; i<=n; ++i) W[i]=read(), rel[i]=read();
for(int u,v,i=1; i<n; ++i) u=read(),v=read(),AddEdge(u,v);
DFS1(1), DFS2(1,1);
for(int i=1; i<=n; ++i) t.Update(1,n,root[rel[i]],id[i],W[i]);
char opt[5]; int x,y;
while(q--)
{
scanf("%s",opt), x=read(), y=read();
switch(opt[1])
{
case 'C': t.Update(1,n,root[rel[x]],id[x],0), rel[x]=y, t.Update(1,n,root[y],id[x],W[x]);
break;
case 'W': t.Update(1,n,root[rel[x]],id[x],y),W[x]=y/*!*/; break;
case 'S': Query_Chain(x,y,1); break;
case 'M': Query_Chain(x,y,0); break;
}
}
return 0;
}

BZOJ.3531.旅行(树链剖分 动态开点)的更多相关文章

  1. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  2. 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)

    题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  3. 【BZOJ3531】[Sdoi2014]旅行 树链剖分+动态开点线段树

    [BZOJ3531][Sdoi2014]旅行 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天 ...

  4. 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

    题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...

  5. [bzoj 3531][SDOI2014]旅行(树链剖分+动态开点线段树)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3531 分析: 对于每个颜色(颜色<=10^5)都建立一颗线段树 什么!那么不是M ...

  6. 2018.07.24 bzoj3531: [Sdoi2014]旅行(树链剖分+动态开点)

    传送门 树链剖分. 如何维护? 如果颜色少直接每种颜色一颗线段树走人. 但这题颜色数量不大于1e5" role="presentation" style="po ...

  7. BZOJ 2157 旅行(树链剖分码农题)

    写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...

  8. bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)

    感觉动态开点线段树空间复杂度好优秀呀 树剖裸题 把每个宗教都开一颗线段树就可以了 但是我一直TLE 然后调了一个小时 为什么呢 因为我 #define max(x, y) (x > y ? x ...

  9. BZOJ 3531(树链剖分+线段树)

    Problem 旅行 (BZOJ 3531) 题目大意 给定一颗树,树上的每个点有两个权值(x,y). 要求维护4种操作: 操作1:更改某个点的权值x. 操作2:更改某个点的权值y. 操作3:求a-- ...

随机推荐

  1. 【PE结构】由浅入深PE基础学习-菜鸟手动查询导出表、相对虚拟地址(RVA)与文件偏移地址转换(FOA)

    0 前言 此篇文章想写如何通过工具手查导出表.PE文件代码编程过程中的原理.文笔不是很好,内容也是查阅了很多的资料后整合出来的.希望借此加深对PE文件格式的理解,也希望可以对看雪论坛有所贡献.因为了解 ...

  2. Hacker需要掌握的基础

    编译语言:1.C语言能力要求:精通选用教材:<C Primer Plus 中文版(第5版)>其他教材:<标准C程序设计(第3版)><C语言入门经典(原书第3版)>补 ...

  3. zabbix系列(十)zabbix添加对zookeeper集群的监控

    1.应用场景描述 在目前公司的业务中,有部分ESB架构用ZooKeeper作为协同服务的场景,做好ZooKeeper的监控很重要. 2.ZooKeeper监控要点 系统监控 内存使用量    ZooK ...

  4. 通达OA在centos系统中快速部署文档(web和数据库)

    通达OA2008从windows环境移植到linux中(centos5.5及以上版本) 如果安装好了,还是无法访问,则需要清空浏览器缓存即可 1.安装lamp环境,这里用的是xampp集成安装包xam ...

  5. centos下常用文件管理命令

    fdisk     d 删除分区     n:新建一个分区     p:列出已有分区     t:调整分区ID     l:列出内核支持的分区id     w:保存退出     q:不保存退出    ...

  6. 解析神奇的 Object.defineProperty

    这个方法了不起啊..vue.js是通过它实现双向绑定的..而且Object.observe也被草案发起人撤回了..所以defineProperty更有必要了解一下了. 几行代码看他怎么用 var a= ...

  7. SeaJS入门教程系列之完整示例(三)

    一个完整的例子上文说了那么多,知识点比较分散,所以最后我打算用一个完整的SeaJS例子把这些知识点串起来,方便朋友们归纳回顾.这个例子包含如下文件: 1.index.html——主页面.2.sea.j ...

  8. php文件路径获取文件名

    物理截取: $file = '/www/htdocs/inc/lib.inc.php'; $filename = basename($file); echo $filename, '<br/&g ...

  9. [PHP] 链表数据结构(单链表)

    链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...

  10. python3 + selenium 多iframe(框架)切换

    html演示: frame.html: <html> <head> <meta http-equiv="content-type" content=& ...