【UOJ261 BZOJ 】天天爱跑步(线段树合并)
来源:互联网 发布:周扬青 淘宝 编辑:程序博客网 时间:2024/05/16 17:37
传送门
天天爱跑步
I Think
题意:给出一颗n个节点的树,每个节点i上有一个仅在时刻
算法:线段树合并
思路:考虑一条路径
1)当S在u的子树内时,若
2)当T在u的子树内时,若
那么计算每个点的答案,则可以建立两颗权值线段树,在树上进行DFS时,自底向上分别在对应权值线段树中插入每个起/终点的贡献
3)当S,T均在u的子树内时,若
实现时可用vector保存以某点为T/LCA的路径。
注意2)操作的权值可能为负,所以左右二式均加上N+1即可。
Code
#include<cstdio>#include<vector>using namespace std;const int sm = 3e5+5;const int sn = 2400000;int N,M,tot,lim;int Rt[2][sm],cnt[2][sn],Ls[2][sn],Rs[2][sn],Lc[sm];int w[sm],S[sm],T[sm],tp,stk[sn],sum[sm],Ans[sm];//bzoj数据较强需要把stk开到比较大 否则WA//sum[i]记从i点出发的路径条数int Fa[sm][22],dep[sm],hd[sm],to[sm<<1],nxt[sm<<1];vector<int > t[sm],lc[sm];//t[i]记在i点结束的路径编号 lc[i]记以i为lca的路径编号template <typename T> void read(T &x) { char ch=getchar();x=0; while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void Swap(int &x,int &y) { int t=x;x=y;y=t; }void Ins(int x,int y) { to[++tot]=y,nxt[tot]=hd[x],hd[x]=tot; to[++tot]=x,nxt[tot]=hd[y],hd[y]=tot;}void Dfsa(int x,int fa) { Fa[x][0]=fa,dep[x]=dep[fa]+1; for(int i=1;i<=19;++i) if(Fa[x][i-1]) Fa[x][i]=Fa[Fa[x][i-1]][i-1]; else break; for(int i=hd[x];i;i=nxt[i]) if(to[i]!=fa) Dfsa(to[i],x);}int Lca(int u,int v) { if(dep[u]!=dep[v]) { if(dep[u]<dep[v]) Swap(u,v); for(int i=19;i>=0;--i) if(dep[Fa[u][i]]>dep[v]) u=Fa[u][i]; u=Fa[u][0]; } if(u==v)return v; for(int i=19;i>=0;--i) if(Fa[u][i]!=Fa[v][i]) u=Fa[u][i],v=Fa[v][i]; return Fa[u][0];}void del(int &x,int k) { stk[++tp]=x,Ls[k][x]=Rs[k][x]=cnt[k][x]=0,x=0;}int Merge(int x,int &y,int k) { if(!(x*y))return x+y; cnt[k][x]+=cnt[k][y]; Ls[k][x]=Merge(Ls[k][x],Ls[k][y],k); Rs[k][x]=Merge(Rs[k][x],Rs[k][y],k); del(y,k); return x;}void Add(int &rt,int l,int r,int p,int val,int k) { if(!rt) { rt = tp? stk[tp--] : ++tot;} cnt[k][rt]+=val; if(l==r) { if(!cnt[k][rt])del(rt,k); return; } int m=(l+r)>>1; if(p<=m) Add(Ls[k][rt],l,m,p,val,k); else Add(Rs[k][rt],m+1,r,p,val,k); if(!Ls[k][rt]&&!Rs[k][rt])del(rt,k);}int Query(int rt,int l,int r,int p,int k) { if(!rt)return 0; if(l==r) return cnt[k][rt]; int m=(l+r)>>1; if(p<=m) return Query(Ls[k][rt],l,m,p,k); else return Query(Rs[k][rt],m+1,r,p,k);}void Dfsb(int x,int fa) { for(int i=hd[x];i;i=nxt[i]) { if(to[i]!=fa) Dfsb(to[i],x); else continue; Rt[0][x]=Merge(Rt[0][x],Rt[0][to[i]],0); Rt[1][x]=Merge(Rt[1][x],Rt[1][to[i]],1); } if(sum[x]) Add(Rt[0][x],1,lim,dep[x],sum[x],0); for(int i=0,p;i<t[x].size();++i) { p=N+1+dep[S[t[x][i]]]-(dep[Lc[t[x][i]]]<<1); Add(Rt[1][x],1,lim,p,1,1); } Ans[x]+=Query(Rt[0][x],1,lim,w[x]+dep[x],0); for(int i=0,p;i<lc[x].size();++i) { //删除以点x为Lca的路径 Add(Rt[0][x],1,lim,dep[S[lc[x][i]]],-1,0); Add(Rt[1][x],1,lim,dep[S[lc[x][i]]]-(dep[x]<<1)+N+1,-1,1); } Ans[x]+=Query(Rt[1][x],1,lim,w[x]-dep[x]+N+1,1);}int main() { read(N),read(M),lim=N<<1|1; for(int i=1,u,v;i<N;++i) read(u),read(v),Ins(u,v); for(int i=1;i<=N;++i) read(w[i]); for(int i=1;i<=M;++i) { read(S[i]),read(T[i]); sum[S[i]]++,t[T[i]].push_back(i); } tot=0,Dfsa(1,0); for(int i=1;i<=M;++i) lc[Lc[i]=Lca(S[i],T[i])].push_back(i); Dfsb(1,0); printf("%d",Ans[1]); for(int i=2;i<=N;++i) printf(" %d",Ans[i]); return 0;}更新一波两颗线段树节点不需区分的代码
#include<vector>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int sn = 3e5 + 19;const int sm = 35e6 + 19;int n,m,lim,tot;int w[sn],ans[sn];int to[sn<<1],nxt[sn<<1],hd[sn],dep[sn];int f[sn][20],S[sn],T[sn],lca[sn],st[sn];vector<int> tt[sn],lc[sn];void Swap(int &x,int &y) { int t = x; x = y; y = t; }void Add(int u,int v) { to[++tot] = v, nxt[tot] = hd[u], hd[u] = tot; to[++tot] = u, nxt[tot] = hd[v], hd[v] = tot;}#define mid ((l+r)>>1)namespace St { int Rt[2][sn],cnt; int val[sm],Ls[sm],Rs[sm]; void Ins(int &rt,int l,int r,int pos,int k) { if(!rt) rt = ++cnt; val[rt] += k; if(l == r) return; if(pos <= mid) Ins(Ls[rt],l,mid,pos,k); else Ins(Rs[rt],mid+1,r,pos,k); } int Query(int rt,int l,int r,int pos) { if(!rt) return 0; if(l == r) return val[rt]; if(pos <= mid) return Query(Ls[rt],l,mid,pos); else return Query(Rs[rt],mid+1,r,pos); } int Merge(int Rt,int rt) { if(!(Rt * rt)) return Rt + rt; val[Rt] += val[rt]; Ls[Rt] = Merge(Ls[Rt],Ls[rt]); Rs[Rt] = Merge(Rs[Rt],Rs[rt]); return Rt; }}using namespace St;void Dfs1(int x,int fa) { f[x][0] = fa, dep[x] = dep[fa]+1; for(int i = 1; i <= 19; ++i) if(f[x][i-1]) f[x][i] = f[f[x][i-1]][i-1]; else break; for(int i = hd[x]; i; i = nxt[i]) if(to[i]!=fa) Dfs1(to[i],x);}int Lca(int u,int v) { if(dep[u] < dep[v]) Swap(u,v); for(int i = 19; i >= 0; --i) if(dep[f[u][i]] >= dep[v]) u = f[u][i]; if(u == v) return v; for(int i = 19; i >= 0; --i) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i]; return f[u][0];}void Dfs2(int x) { for(int i = hd[x]; i; i = nxt[i]) if(to[i] != f[x][0]) { Dfs2(to[i]); Rt[0][x] = Merge(Rt[0][x],Rt[0][to[i]]); Rt[1][x] = Merge(Rt[1][x],Rt[1][to[i]]); } if(st[x]) Ins(Rt[0][x],1,lim,dep[x],st[x]); int loc; for(int i = 0,num; i < tt[x].size(); ++i) { num = tt[x][i]; loc = dep[S[num]]-(dep[lca[num]]<<1)+n+1; Ins(Rt[1][x],1,lim,loc,1); } ans[x] = Query(Rt[1][x],1,lim,w[x]-dep[x]+n+1); for(int i = 0,num; i < lc[x].size(); ++i) { num = lc[x][i]; loc = dep[S[num]]-(dep[x]<<1)+n+1; Ins(Rt[1][x],1,lim,loc,-1); Ins(Rt[0][x],1,lim,dep[S[num]],-1); } ans[x] += Query(Rt[0][x],1,lim,dep[x]+w[x]);}int main() { int u,v; scanf("%d%d",&n,&m); for(int i = 1; i < n; ++i) scanf("%d%d",&u,&v), Add(u,v); for(int i = 1; i <= n; ++i) scanf("%d",&w[i]); for(int i = 1; i <= m; ++i) { scanf("%d%d",&S[i],&T[i]); ++st[S[i]]; tt[T[i]].push_back(i); } Dfs1(1,0); for(int i = 1; i <= m; ++i) lc[lca[i] = Lca(S[i],T[i])].push_back(i); lim = n<<1|1, Dfs2(1); for(int i = 1; i <= n; ++i) printf("%d ",ans[i]); putchar(10); return 0;}
阅读全文
0 0
- 【UOJ261 BZOJ 】天天爱跑步(线段树合并)
- [UOJ261]天天爱跑步
- bzoj 4719: [Noip2016]天天爱跑步 线段树合并
- NOIP2016D1T2 天天爱跑步 BZOJ4719 UOJ261
- 【NOIP2016】【合并线段树】D1T2 天天爱跑步 题解
- UOJ261 NOIP2016 day1 T2 天天爱跑步 (lca + 桶 )
- [NOIP2016] 天天爱跑步 LCA 树上差分 线段树
- 【bzoj 4719】[Noip2016]天天爱跑步
- BZOJ 4719: [Noip2016]天天爱跑步 tarjanlca
- 天天爱跑步
- NOIP2016 天天爱跑步
- P1600 天天爱跑步
- [NOIP2016]天天爱跑步
- [NOIP2016]天天爱跑步
- NOIP2016 天天爱跑步
- NOIP2016 天天爱跑步
- LCA 天天爱跑步
- 天天爱跑步NOIP
- [10] Linux系统日常运维
- 多行数据输出与处理
- 2016 Pacific Northwest Region Programming Contest—Division 2 Problem R — limit 1 second Equality
- Intel P6以来核心架构及对应型号、芯片组一览表
- Fragment replace的使用
- 【UOJ261 BZOJ 】天天爱跑步(线段树合并)
- leetcode -- 345. Reverse Vowels of a String 【双指针 + 逆序的变形】
- Mybatis:ReflectionException: There is no getter for property named 'productName' in 'class java.lang
- 搜索 棋盘问题
- 内存的几个小问题
- codeforces 821d Okabe and City
- 安装Python3-ipython
- NKOJ 3252 (CQOI 2015) 多项式(数学,高精度)
- 暑期集训之最大公约数问题