HDU 5893List wants to travel(树链剖分-区间合并-区间更新-入边)
来源:互联网 发布:网络管理视频教程下载 编辑:程序博客网 时间:2024/05/16 19:34
题意:
找书上路径的有多少种不同颜色的更换
思路:
和网上说的一样。。先刷了染色(树链剖分-入点)再来刷这题。。然而发现和直接给点权值不同,给边权值显然麻烦的多,做了两个小时,也没讨论清楚。找了篇思路清晰的博客改了改查询部分就AC了。查询部分有详细注释,就不多记录了,当板子直接上代码
#include <map>#include <set>#include <queue>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAXN = 40010;struct node { int left,right; int left_color,right_color; int sum; int lazy;}t[MAXN*4];struct Edge{ int to,next,w;} edge[MAXN<<1];int fa[MAXN],son[MAXN],siz[MAXN],dep[MAXN],top[MAXN],id[MAXN],val[MAXN];int n,q;int col[MAXN];int topw= 0;int tot ,head[MAXN];int cnt=0;int fp[MAXN];void dfs1(int u,int f,int d){ dep[u]=d; siz[u]=1; fa[u]=f; for(int i =head[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if(v==fa[u]) continue; val[v]=edge[i].w; dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]||son[u]==-1) son[u]=v; }}void getpos(int u,int sp){ top[u] = sp; id[u] =++topw; ///id是点的编号,fp[id[u]]是一个对于点与自身编号的映射 fp[id[u]] = u; if(son[u] == -1)return ; getpos(son[u],sp); for(int i = head[u]; ~i ; i = edge[i].next) { int v = edge[i].to; if(v != son[u] && v != fa[u]) getpos(v,v); }}void push_up(int i){ t[i].sum=t[i<<1].sum+t[i<<1|1].sum; if(t[i<<1].right_color==t[i<<1|1].left_color) t[i].sum--; t[i].right_color=t[i<<1|1].right_color; t[i].left_color=t[i<<1].left_color;}void push_down(int i){ if(t[i].lazy) { t[i<<1|1].lazy=t[i<<1].lazy=t[i].lazy; t[i<<1].left_color=t[i<<1].right_color=t[i].lazy; t[i<<1|1].left_color=t[i<<1|1].right_color=t[i].lazy; t[i<<1|1].sum=t[i<<1].sum=t[i].sum; t[i].lazy=0; }}void build(int i,int left,int right){ t[i].left=left,t[i].right=right,t[i].lazy=0; if(left==right) { t[i].left_color=val[fp[left]]; t[i].right_color=val[fp[left]]; t[i].sum=1; return ; } int mid=(t[i].left+t[i].right)>>1; build(i<<1,left,mid); build(i<<1|1,mid+1,right); push_up(i); return ;}void update(int i,int left,int right,int w){ if(left<=t[i].left&&t[i].right<=right) { t[i].lazy=w; t[i].left_color=t[i].right_color=w; t[i].sum=1; return ; } push_down(i); int mid=(t[i].left+t[i].right)>>1; if(mid>=left) { update(i<<1,left,right,w); } if(mid<right) { update(i<<1|1,left,right,w); } push_up(i);}int right_color = 0;int ANS = 0;///这个查询部分处理效果为: 在查一段区间时,如果左侧线段树的右端等于右侧线段树的左端就--,基本的线段树的区间合并的应用node query(int rt,int l,int r,int L,int R){ if(L<=l && r<=R) { return t[rt]; } push_down(rt); int mid = (l+r) >> 1; if(R<=mid) return query(rt<<1,l,mid,L,R); else if(L>mid) return query(rt<<1|1,mid+1,r,L,R); else { node p1 = query(rt<<1,l,mid,L,R); node p2 = query(rt<<1|1,mid+1,r,L,R); node res; res.sum = p1.sum + p2.sum; res.left_color = p1.left_color; res.right_color = p2.right_color; if(p1.right_color==p2.left_color) res.sum--; return res; }}int solve(int x,int y){ int ans = 0; int cx=-1,cy=-1; ///对于每个树链剖分的效果来说,先处理深度大的部分,这样每次会得到一个当前处理链部分的顶端left_color 保存为cx, 如果下一次链的末端 ///与顶端cx颜色相同就 -- while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) { swap(x,y);swap(cx,cy); } node tmp = query(1,1,n,id[top[x]],id[x]); ans += tmp.sum; if(tmp.right_color==cx) ans--; cx = tmp.left_color; x = fa[top[x]]; } ///如果x某一次结果恰好是y的轻链的父节点,那么此时会跑到x==y的情况,既然如此就需要减去当前点的值 if(x==y) { if(cx==cy)ans--; return ans; } ///如果x,y为同一条重链上的情况: ///判断之前的链与当前链的关系: 因为 cy初始必定为-1,需要判断前一条链与当前链的关系 ///如果x,从某条轻链转移到此重链,然而dep[x]仍然比dep[y]小,那么y在x的上面,因此找的时候直接找cx和tmp的末端,反之同理 if(dep[x]<dep[y]) { swap(x,y);swap(cx,cy); } node tmp = query(1,1,n,id[son[y]],id[x]); ans += tmp.sum; if(tmp.left_color == cy) ans--; if(tmp.right_color == cx) ans--; return ans;}void change(int u,int v,int w){ int tpu=top[u],tpv=top[v]; while(tpu!=tpv) { if(dep[tpu]<dep[tpv]) { swap(u,v); swap(tpu,tpv); } update(1,id[tpu],id[u],w); u=fa[tpu]; tpu=top[u]; } if(u==v) return ; if(dep[u]>dep[v]) swap(u,v); update(1,id[son[u]],id[v],w);}void addedge(int u,int v,int w){ edge[tot].w = w,edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;}int main(){ while(~scanf("%d%d",&n,&q) ) { topw=0,tot=0; memset(son,-1,sizeof(son)); memset(head,-1,sizeof(head)); int u,v,w,a,b,c; for(int i =1; i < n; i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } dfs1(1,0,1); getpos(1,1); build(1,1,topw); char op[5]; int color; while(q--) { scanf("%s",op) ; if(op[0] == 'C') { scanf("%d %d %d",&u,&v,&color); change(u,v,color); } else { scanf("%d %d",&u,&v); if(u==v) { printf("0\n"); continue; } int ans = 0; ans += solve(u,v); printf("%d\n",ans); } } } return 0;}/*9 101 2 22 3 11 7 21 4 23 5 23 6 15 8 25 9 3Query 2 3Q 8 9Q 1 8*/
阅读全文
0 0
- HDU 5893List wants to travel(树链剖分-区间合并-区间更新-入边)
- [HDU 5893] List wants to travel (树链剖分+区间合并)
- HDU 5893 List wants to travel(树链剖分+区间合并)
- HDU 5893 List wants to travel (树链剖分,线段树区间合并)
- hdu 5893 List wants to travel 树链剖分求区间段数
- 2016 ACM/ICPC Reginal Shengyang hdu 5893 List wants to travel(树链剖分 线段树区间更新真蛋疼)★
- HDU 5893 List wants to travel 树链剖分求区间不同段个数
- Hdu-5893 List wants to travel(树链剖分)
- [树链剖分] HDU 5893 List wants to travel
- HDU 5893 List wants to travel 树链剖分
- HDU 5893 List wants to travel
- hdu 5893 List wants to travel
- HDU 5893 List wants to travel
- hdu 5893 List wants to travel 树链剖分 +线段树
- HDU 5893 List wants to travel 树链剖分 边权剖分
- HDU 5893 List wants to travel 【线段树+树链剖分】
- List wants to travel
- hdu5893 List wants to travel
- 8.23模拟赛
- 在QT实现文件传输
- STL学习笔记——关联式容器(二级容器)
- web前端RxJS初步学习
- LintCode-----31.数组划分
- HDU 5893List wants to travel(树链剖分-区间合并-区间更新-入边)
- log4j 详细讲解
- unity3d 5.6烘焙教程 持续更新中
- 如何把JAVA程序做成Windows服务,并开机运行
- 断点续传大文件,视频
- GitHub上传代码的方法以及出现的一些错误的解决办法
- 水题:UVa489-Hangman Judge
- 一分钟了解"形容背景很复杂的英语词汇"
- 第7讲项目2-输出最大值