[SDOI2014]旅行

题意:

n个城市,n-1条边,任意两个城市互通,每个城市有所信奉的宗教和城市评级,有四种指令:
1.将城市x的居民改信为c教
2.将城市x的评级调整为w
3.统计x到y,路上所有的城市的评级综合(被记录的城市宗教必须与x和y相同,数据保证x和y宗教一致)
4.统计x到y,路上的评级最大值(被记录的城市要求与上述一样)
按照要求输出答案

题解:

参考文章为洛谷题解的第一篇(文章好像显示不可查看
洛谷的题解第一页
题目比较麻烦,因为有两个要维护的量,如果是一个还好说,对于树上维护那肯定是树链剖分,现在关键就是如果确保只统计同一宗教的评级
我们可以将每个宗教建立一个线段树这样分开维护不久ok了,但是内存会超,那我们就主席树,动态开点
现在讲讲具体细节:
动态开点就不说了
我们讲讲改信其他教和评级调整如何实现?
原本是a教,改成c教
那我们就先到a教的线段树中找到这个点,然后将其评级和评级最大值都清零(可以理解为删除这个点,但实际还存在只是没有值),然后到c教里将这个点再加上,并加上评级
注意:在删除过程中记得要pushup(root),你删除一个点后,整个数的最大值和权值和发生了改变,所以即可更新到根节点
评级更新也是差不多,先把原本评级删去,再附上新评级
剩下都是树链剖分常规操作
代码有详细注释

代码:

#include<bits/stdc++.h>
using namespace std;
struct node{int to,next;
}g[1000000];
int tot,n,m,cnt,w[100004],zj[100004],len,head[100004],dep[100004],wson[100004],top[100004],tpos[100004],pre[100004],fa[100004],size[100004];
inline void made(int from,int to){g[++tot].to=to;g[tot].next=head[from];head[from]=tot;
}
inline void dfs1(int rt,int ff){fa[rt]=ff;dep[rt]=dep[ff]+1;size[rt]=1;for (int i=head[rt];i;i=g[i].next){int v=g[i].to;if (v==ff) continue;dfs1(v,rt);size[rt]+=size[v];if (!wson[rt]||size[wson[rt]]<size[v]) wson[rt]=v;}
}
inline void dfs2(int rt,int tops){tpos[rt]=++cnt;pre[cnt]=rt;top[rt]=tops;if (wson[rt]) dfs2(wson[rt],tops);for (int i=head[rt];i;i=g[i].next){int v=g[i].to;if (v==fa[rt]||v==wson[rt]) continue;dfs2(v,v);}
}
int root[100004];
struct Node{int l,r,max,tot;
}tree[20000110];
inline void update(int &rt,int w,int l,int r,int pos){//加点操作 if (!rt) rt=++len;//动态开点 tree[rt].max=max(tree[rt].max,w);tree[rt].tot+=w;if (l==r) return;int mid=(l+r)/2;if (mid>=pos) update(tree[rt].l,w,l,mid,pos);else update(tree[rt].r,w,mid+1,r,pos);
}
inline void remove(int &rt,int l,int r,int pos){//删点操作 if (l==r){ tree[rt].tot=0;tree[rt].max=0;return; }int mid=(l+r)/2;if (mid>=pos) remove(tree[rt].l,l,mid,pos);else remove(tree[rt].r,mid+1,r,pos);tree[rt].tot=tree[tree[rt].l].tot+tree[tree[rt].r].tot;tree[rt].max=max(tree[tree[rt].l].max,tree[tree[rt].r].max);
}inline int querytot(int rt,int lb,int rb,int l,int r){//查询区间总值 if (r<lb||l>rb) return 0;if (r>=rb&&l<=lb) return tree[rt].tot;int mid=(lb+rb)/2;return querytot(tree[rt].l,lb,mid,l,r)+querytot(tree[rt].r,mid+1,rb,l,r);
}
inline int querymax(int rt,int lb,int rb,int l,int r){//查询区间最大值 if (r<lb||l>rb) return 0;if (r>=rb&&l<=lb) return tree[rt].max;int mid=(lb+rb)/2;return max(querymax(tree[rt].l,lb,mid,l,r),querymax(tree[rt].r,mid+1,rb,l,r));
}
//--上面为动态开点线段树,下面为树链剖分
inline int sigmax(int u,int v,int zj){int ans=0;while (top[u]!=top[v]){if (dep[top[u]]<dep[top[v]]) swap(u,v);ans=max(ans,querymax(root[zj],1,n,tpos[top[u]],tpos[u]));u=fa[top[u]];}if (dep[u]<dep[v]) swap(u,v);ans=max(ans,querymax(root[zj],1,n,tpos[v],tpos[u]));return ans;
}
inline int sigtot(int u,int v,int zj){int ans=0;while (top[u]!=top[v]){if (dep[top[u]]<dep[top[v]]) swap(u,v);ans=ans+querytot(root[zj],1,n,tpos[top[u]],tpos[u]);u=fa[top[u]];}if (dep[u]<dep[v]) swap(u,v);ans=ans+querytot(root[zj],1,n,tpos[v],tpos[u]);return ans;
}
char s[100];
int main(){len=0;scanf("%d%d",&n,&m);for (int i=1;i<=n;i++){scanf("%d%d",&w[i],&zj[i]);}int x,y;for (int i=1;i<n;i++){scanf("%d%d",&x,&y);made(x,y);made(y,x);}dfs1(1,0);dfs2(1,1);for (int i=1;i<=n;i++){update(root[zj[i]],w[i],1,n,tpos[i]);}     while (m--){scanf("%s",s);scanf("%d%d",&x,&y);switch (s[1]){case 'C':{//改信了c教 remove(root[zj[x]],1,n,tpos[x]);zj[x]=y;update(root[zj[x]],w[x],1,n,tpos[x]);break;}case 'W':{//城市x的评级调整为w;remove(root[zj[x]],1,n,tpos[x]);w[x]=y;update(root[zj[x]],w[x],1,n,tpos[x]);break;}case 'S':{//记录评级总和 printf("%d\n",sigtot(x,y,zj[x]));break;} case 'M':{//记录评级最大值 printf("%d\n",sigmax(x,y,zj[x]));break;}}}return 0;
}

[SDOI2014]旅行相关推荐

  1. BZOJ 3531[Sdoi2014]旅行

    BZOJ 3531[Sdoi2014]旅行 题面描述 传送门 题目分析 可以考虑到,如果这个题所有城市都只信一种宗教的话,就是一个sb树剖,直接进行链的查询和修改就能搞定.多个宗教的话,可以有一种暴力 ...

  2. 【bzoj 3531】 [Sdoi2014]旅行(树链剖分+树套树)

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1197  Solved: 576 [Submit][Statu ...

  3. ZOJ3531: [SDOI2014] 旅行

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

  4. [bzoj3531][Sdoi2014]旅行

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

  5. luogu_P3313 [SDOI2014]旅行

    传送门 Solution 第二次学习可持久化线段树 打了一道裸题来练习一下-- 对于每个宗教都可以开一个主席树 基础操作 树剖lca Code #include<bits/stdc++.h> ...

  6. SDOI2014 旅行

    传送门 省选前水一发 这题一开始看标签是主席树--后来--这题和主席树有啥关系-- 可以想到对于每种宗教用树剖+线段树维护即可.然后因为空间不够要动态开点.然后改宗教,改评级的,把原来的点删了再插一个 ...

  7. [BZOJ 3531] [Sdoi2014] 旅行 【离线+LCT】

    题目链接:BZOJ - 3531 题目分析 题目询问一条路径上的信息时,每次询问有某种特定的文化的点. 每个点的文化就相当于一种颜色,每次询问一条路径上某种颜色的点的信息. 可以使用离线算法, 类似于 ...

  8. BZOJ3531旅行

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 942 Solved: 467 Description S国有N个 ...

  9. 动态开点线段树(多棵线段树)的内存分配与回收

    前言 线段树,是一个很好用的能支持O(logn)区间操作的数据结构,随着做一些稍微烦一点的题,有时候会发现有些情况要开一个数组的线段树,更有甚者要树套树,而在很多情况下线段树就不能把所有点都开满了(否 ...

最新文章

  1. Android Studio 编译: Program type already present: XXX 解决方案
  2. 生产者/消费者问题的多种Java实现方式
  3. 分布式存储-ceph
  4. 图片怎么等比缩放_mac图像缩放工具Teorex iResizer
  5. protocol_buffers简易操作
  6. 计算机原理寄存器基础知识,微机原理——基础知识及计算机基本组成
  7. Centos升级安装.Net core 1.1
  8. lisp 线性标注自动避让_本科阶段就挑战自动驾驶开发?华为云ModelArts说Yes!
  9. 如何制作SCI论文中的Figure(二)
  10. Opencv3与Opencv2的区别,及opencv2项目移植到opencv3注意事项
  11. git动图快速制作方法
  12. 0016 c/c++语言 二进制转换为十进制
  13. 被病毒感染后隐藏文件夹的隐藏属性变灰(不可修改)的解决办法!
  14. gif录制软件:ScreenToGif
  15. mysql5.1.40.jrp_1.原生态JDBC编程中的问题总结
  16. 计算机网络安全控制技术
  17. mysql课设的心得体会_关于数据库课设的感想
  18. 产品体验营销或成广告业主们的新选择
  19. 智能园区中计算机网络结构,工业园区智能化统设计方案.ppt
  20. oracle导入dmp时IMP-00013错误

热门文章

  1. 放弃Python转向Go语言:我们找到了以下9大理由
  2. 5码默认版块_5个小众的生活学习类的宝藏App
  3. java 子类 复制_关于java子类继承来的属性与方法究竟是完全复制还是共用使用...
  4. java final 修改_“无法改变的设计”——浅谈Java中的final关键字
  5. 一个问题让我直接闭门思过!!!拼多多面试必问项之List实现类:LinkedList
  6. php 获取对象所有成员变量,PHP成员变量获取对比
  7. php 初始二维数组长度,php二维数组排序与默认自然排序的方法介绍
  8. java buffalo_随你怎么玩!Buffalo 网络硬盘新潮流
  9. c语言歌手预测成绩,5个裁判可以对10个歌手进行打分,计算各个歌手的最终得分排列...
  10. android arp工具,GitHub - SummerSnow274/ARP_sed_rev: 在Android通过ARP询问实现获取同一网络所有设备的MAC地址,AP隔离的网络除外...