BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门
完了今天才知道原来线段树的动态开点和主席树是不一样的啊
我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和
然后有了宗教信仰的限制该怎么做呢?
先考虑暴力,对每一个信仰建一棵线段树
然而必然会MLE
于是我们只能动态开点
说一下我自己的理解吧,动态开点就是把那些建树过程中没有用的节点删去,以此来节省空间
比如当$sum[p]=0$时,直接删去点$p$
具体实现还是参考一下代码吧
1 // luogu-judger-enable-o2 2 //minamoto 3 #include<bits/stdc++.h> 4 #define N 300005 5 using namespace std; 6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 7 inline int read(){ 8 #define num ch-'0' 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getchar())) 11 (ch=='-')&&(flag=true); 12 for(res=num;isdigit(ch=getchar());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 int L[N<<2],R[N<<2],mx[N<<2],sum[N<<2]; 18 int sz[N],fa[N],son[N],dfn[N],rk[N],d[N],top[N],val[N],c[N]; 19 int ver[N<<1],head[N],Next[N<<1],yval[N],yc[N]; 20 int rt[N]; 21 int n,m,num,tot,cnt; 22 inline void add(int u,int v){ 23 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 24 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 25 } 26 void dfs1(int u){ 27 sz[u]=1,d[u]=d[fa[u]]+1; 28 for(int i=head[u];i;i=Next[i]){ 29 if(ver[i]==fa[u]) continue; 30 int v=ver[i]; 31 fa[v]=u; 32 dfs1(v); 33 sz[u]+=sz[v]; 34 if(!son[u]||sz[v]>sz[son[u]]) son[u]=v; 35 } 36 } 37 void dfs2(int u){ 38 if(!top[u]) top[u]=u; 39 dfn[u]=++num,rk[num]=u; 40 if(!son[u]) return; 41 top[son[u]]=top[u],dfs2(son[u]); 42 for(int i=head[u];i;i=Next[i]){ 43 int v=ver[i]; 44 if(v!=fa[u]&&v!=son[u]) dfs2(v); 45 } 46 } 47 void update(int p){ 48 mx[p]=max(mx[L[p]],mx[R[p]]); 49 sum[p]=sum[L[p]]+sum[R[p]]; 50 } 51 void modify(int &p,int l,int r,int k,int v){ 52 if(!p) p=++cnt; 53 if(l>=r){ 54 mx[p]=sum[p]=v;return; 55 } 56 int mid=(l+r)>>1; 57 if(k<=mid) modify(L[p],l,mid,k,v); 58 else modify(R[p],mid+1,r,k,v); 59 update(p); 60 if(sum[p]==0) p=0; 61 } 62 int askmax(int p,int l,int r,int ql,int qr){ 63 if(!p) return -1; 64 if(ql<=l&&qr>=r) return mx[p]; 65 int mid=(l+r)>>1,val=-1; 66 if(ql<=mid) cmax(val,askmax(L[p],l,mid,ql,qr)); 67 if(qr>mid) cmax(val,askmax(R[p],mid+1,r,ql,qr)); 68 return val; 69 } 70 int asksum(int p,int l,int r,int ql,int qr){ 71 if(!p) return 0; 72 if(ql<=l&&qr>=r) return sum[p]; 73 int mid=(l+r)>>1,val=0; 74 if(ql<=mid) val+=asksum(L[p],l,mid,ql,qr); 75 if(qr>mid) val+=asksum(R[p],mid+1,r,ql,qr); 76 return val; 77 } 78 int path_max(int u,int v){ 79 int ans=-1; 80 int xz=yc[u]; 81 while(top[u]!=top[v]){ 82 if(d[top[u]]<d[top[v]]) swap(u,v); 83 cmax(ans,askmax(rt[xz],1,num,dfn[top[u]],dfn[u])); 84 u=fa[top[u]]; 85 } 86 if(d[u]<d[v]) swap(u,v); 87 cmax(ans,askmax(rt[xz],1,num,dfn[v],dfn[u])); 88 return ans; 89 } 90 int path_sum(int u,int v){ 91 int ans=0; 92 int xz=yc[u]; 93 while(top[u]!=top[v]){ 94 if(d[top[u]]<d[top[v]]) swap(u,v); 95 ans+=asksum(rt[xz],1,num,dfn[top[u]],dfn[u]); 96 u=fa[top[u]]; 97 } 98 if(d[u]<d[v]) swap(u,v); 99 ans+=asksum(rt[xz],1,num,dfn[v],dfn[u]); 100 return ans; 101 } 102 int main(){ 103 //freopen("testdata.in","r",stdin); 104 int n,q; 105 n=read(),q=read(); 106 for(int i=1;i<=n;++i) 107 yval[i]=read(),yc[i]=read(); 108 for(int i=1;i<n;++i){ 109 int u=read(),v=read(); 110 add(u,v); 111 } 112 dfs1(1),dfs2(1); 113 for(int i=1;i<=n;++i) 114 modify(rt[yc[rk[i]]],1,num,i,yval[rk[i]]); 115 while(q--){ 116 char s[10];int x,y; 117 scanf("%s",s); 118 x=read(),y=read(); 119 switch(s[1]){ 120 case 'C':{ 121 modify(rt[yc[x]],1,num,dfn[x],0); 122 yc[x]=y; 123 modify(rt[yc[x]],1,num,dfn[x],yval[x]); 124 break; 125 } 126 case 'W':{ 127 yval[x]=y; 128 modify(rt[yc[x]],1,num,dfn[x],yval[x]); 129 break; 130 } 131 case 'S':{ 132 printf("%d\n",path_sum(x,y)); 133 break; 134 } 135 case 'M':{ 136 printf("%d\n",path_max(x,y)); 137 break; 138 } 139 } 140 } 141 return 0; 142 }
转载于:https://www.cnblogs.com/bztMinamoto/p/9398077.html
BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)相关推荐
- P3292 [SCOI2016]幸运数字(树剖 + 线段树维护线性基)
P3292 [SCOI2016]幸运数字 思路 如果这题是求x,yx, yx,y之间的距离显然我们可以通过树剖加线段树来写, 但是这里变成了求任意个数的异或最大值.如果给定区间我们显然可以通过线性基来 ...
- BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)
题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...
- BZOJ4034 树上操作(树剖 线段树大模板)
BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #inc ...
- 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”
题面:月下"毛景树" 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来, ...
- 2019ICPC西安邀请赛 E. Tree(树剖 + 线段树)
Tree 给定一棵树,节点有点权,然后有三种操作: 一.修改1−>s1->s1−>s的路径上的点权与ttt进行按位或. 二.修改1−>s1->s1−>s的路径上的点 ...
- ural 1553 树剖+线段树
//链式前向星版 #include<bits/stdc++.h> using namespace std; const int maxn=100010; //建图 int to[maxn* ...
- #HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MB Description 给出一个n个节点的有根树(编号为0到n-1,根节点为 ...
- 2021 Jiangsu Collegiate Programming Contest F. Jumping Monkey II 树剖+线段树
F. Jumping Monkey II 题意: 给你 n = 2 e 5 n=2e5 n=2e5的一棵树,每个点有点权 a [ i ] < = 1 e 9 a[i]<=1e9 a[i]& ...
- 洛谷2543AHOI2005]航线规划 (树剖+线段树+割边思路)
这个题的思路还是比较巧妙的. 首先,我们发现操作只有删除和询问两种,而删除并不好维护连通性和割边之类的信息. 所以我们不妨像WC2006水管局长那样,将询问离线,然后把操作转化成加边和询问. 然后,我 ...
最新文章
- DevTools 实现原理与性能分析实战
- java判断一个单向链表是否有环路
- Keras MNIST
- oracle导出pdm文件命令,利用PowerDesigner逆向工程导出PDM模型及生成文档
- [网络流24题] 航空路线问题 (费用流)
- 【转】开机出现 error:file “/boot/grub/i386-pc/normal.mod“ not found 错误提示
- 【批处理】windows环境将文件放置在虚拟盘
- 年赚133亿!中国平安旗下陆金所向SEC递交招股书
- java时间格式转换_Java时间日期格式转换
- 我是这样在第一轮筛选简历的
- Web Clip 图片变淡变浅变灰解决方案
- 分享webStorm汉化
- 沙盘模拟软件_三连冠!我校学子连续三年蝉联全国大学生沙盘模拟经营大赛福建省决赛一等奖...
- sqlserver用sql语句备份数据库
- android模拟机神器[Genymotion]的使用
- 【bat】做个一键连接网络打印机的bat
- 最有效地戒掉晚睡强迫症(熬夜强迫症、假象失眠症等等)
- C# 串口接收的优化处理
- Error: Java exception was raised during method invocation
- 学以致用——微博文章内容统计分析之一(Excel+GraphLab)