bzoj4448 [Scoi2015]情报传递(树链剖分+主席树)
2018-02-10 21:23
465 查看
题目链接
分析:
树上路径问题,显然可以链剖
看完题的我,大脑中浮现的想法↓:
对于每一个修改,在按照树链剖分建立的线段树上单点修改
记录这个点是什么时刻进行的修改
之后在询问的时候,我们只需查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点即可
那么我们就可在线段树里套一个权值平衡树
这道题的题解:树链剖分+线段树+平衡树
我的MA呀,不觉得神烦吗???
实际上我们的问题就出在:查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点
按照在dfs序建立主席树,在主席树上处理完所有的修改操作
询问时直接利用树链剖分在主席树张区间查询即可
这样问题就迎刃而解了
在码的时候,突然有点绕不过来了:
主席树肯定建立在dfs序上的权值线段树
但是在询问的时候有时间限制,怎么破?
后来我才发现是我傻。。。
我们在主席树中记录的就是添加修改的时间点
只要查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点即可
和询问出现的时间没有什么直接联系
(间接联系:时间已经体现在“当前时刻-C-1”的这个“当前时刻”中了)
一开始WA了一次
因为我对于没有修改的结点在主席树上没有插入,只有root的继承
后来改成对于没有修改的结点在主席树上插入m,就A了
分析:
树上路径问题,显然可以链剖
看完题的我,大脑中浮现的想法↓:
对于每一个修改,在按照树链剖分建立的线段树上单点修改
记录这个点是什么时刻进行的修改
之后在询问的时候,我们只需查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点即可
那么我们就可在线段树里套一个权值平衡树
这道题的题解:树链剖分+线段树+平衡树
我的MA呀,不觉得神烦吗???
实际上我们的问题就出在:查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点
我们可以用主席树完成
我们把所有操作离线按照在dfs序建立主席树,在主席树上处理完所有的修改操作
询问时直接利用树链剖分在主席树张区间查询即可
这样问题就迎刃而解了
tip
自从理解了线段树套平衡树之后,做题就很喜欢往这方面想。。。在码的时候,突然有点绕不过来了:
主席树肯定建立在dfs序上的权值线段树
但是在询问的时候有时间限制,怎么破?
后来我才发现是我傻。。。
我们在主席树中记录的就是添加修改的时间点
只要查找区间内有多少时间戳小于等于“当前时刻-C-1”的结点即可
和询问出现的时间没有什么直接联系
(间接联系:时间已经体现在“当前时刻-C-1”的这个“当前时刻”中了)
一开始WA了一次
因为我对于没有修改的结点在主席树上没有插入,只有root的继承
后来改成对于没有修改的结点在主席树上插入m,就A了
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=200005; int n,m,root ,rt,cntC=0,cntQ=0,sz=0,tt; int deep ,top ,pre ,num ,dfn ,clo=0,size ,son ; struct point{ int ti,x,y; }; point C ,Q ; struct po{ int y,nxt; }; po way ; int st ,tot=0; struct node{ int sum,l,r; }; node t[N*20]; void add(int u,int w) { tot++; way[tot].y=w;way[tot].nxt=st[u];st[u]=tot; } void dfs_1(int now,int fa,int dep) { deep[now]=dep; pre[now]=fa; size[now]=1; int maxx=0; for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa) { dfs_1(way[i].y,now,dep+1); size[now]+=size[way[i].y]; if (size[way[i].y]>maxx) maxx=size[way[i].y],son[now]=way[i].y; } } void dfs_2(int now,int fa) { if (son[fa]!=now) top[now]=now; else top[now]=top[fa]; dfn[++clo]=now; num[now]=clo; if (son[now]) { dfs_2(son[now],now); for (int i=st[now];i;i=way[i].nxt) if (way[i].y!=fa&&way[i].y!=son[now]) dfs_2(way[i].y,now); } } void insert(int &now,int l,int r,int x) { sz++; t[sz]=t[now]; now=sz; t[now].sum++; if (l==r) return; int mid=(l+r)>>1; if (x<=mid) insert(t[now].l,l,mid,x); else insert(t[now].r,mid+1,r,x); } void ask(int x,int y,int l,int r,int z) { if (l==r) { if (l<=z) tt+=t[y].sum-t[x].sum; return; } int mid=(l+r)>>1; int tmp=t[t[y].l].sum-t[t[x].l].sum; if (z<=mid) ask(t[x].l,t[y].l,l,mid,z); else tt+=tmp,ask(t[x].r,t[y].r,mid+1,r,z); } int query(int o) { int x=Q[o].x,y=Q[o].y; int len=deep[x]+deep[y],ans=0; int f1=top[x],f2=top[y]; while (f1!=f2) { if (deep[f1]<deep[f2]) swap(f1,f2),swap(x,y); tt=0; ask(root[num[f1]-1],root[num[x]],1,m,Q[o].ti); ans+=tt; x=pre[f1]; f1=top[x]; } if (deep[x]>deep[y]) swap(x,y); tt=0; ask(root[num[x]-1],root[num[y]],1,m,Q[o].ti); ans+=tt; len=len-2*deep[x]+1; printf("%d %d\n",len,ans); } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { int x; scanf("%d",&x); if (!x) rt=i; else add(x,i); } dfs_1(rt,0,1); dfs_2(rt,0); scanf("%d",&m); int opt,x,y,c; for (int i=1;i<=m;i++) { scanf("%d",&opt); if (opt==1) { cntQ++; scanf("%d%d%d",&Q[cntQ].x,&Q[cntQ].y,&Q[cntQ].ti); Q[cntQ].ti=i-Q[cntQ].ti-1; } else { scanf("%d",&x); C[x].ti=i; } } for (int i=1;i<=n;i++) { root[i]=root[i-1]; if (C[dfn[i]].ti!=0) insert(root[i],1,m,C[dfn[i]].ti); else insert(root[i],1,m,m); //插入m } for (int i=1;i<=cntQ;i++) query(i); return 0; }
相关文章推荐
- BZOJ 4448: [Scoi2015]情报传递 树链剖分 主席树
- 【BZOJ 4448】 [Scoi2015]情报传递|倍增LCA|主席树
- bzoj 4448 [Scoi2015]情报传递(主席树,LCA)
- [BZOJ4448][Scoi2015]情报传递(主席树)
- BZOJ_4448_[Scoi2015]情报传递_主席树
- [BZOJ4448][Scoi2015]情报传递(树上主席树)
- [BZOJ4448][Scoi2015]情报传递(树上主席树)
- 【bzoj4448】[Scoi2015]情报传递 主席树
- 【BZOJ4448】[Scoi2015]情报传递 主席树+LCA
- bzoj 4448: [Scoi2015]情报传递 (树上主席树)
- 【BZOJ 4448】 [Scoi2015]情报传递|树链剖分|树套树
- BZOJ 4448: [Scoi2015]情报传递 树剖套主席树
- bzoj 4448: [Scoi2015]情报传递
- bzoj 4448: [Scoi2015]情报传递
- 4448: [Scoi2015]情报传递|主席树|离线操作
- 【bzoj4448】SCOI2015 情报传递
- bzoj 4448: [Scoi2015]情报传递 可持久化线段树+离线
- 4448: [Scoi2015]情报传递 dfs序+主席树
- 4448: [Scoi2015]情报传递|主席树|离线操作
- [bzoj4448] [Scoi2015]情报传递