您的位置:首页 > 其它

【bzoj 4448】 [Scoi2015]情报传递 离线+树剖+树状数组

2016-10-03 14:50 281 查看
老师是想让我们练习树套树的时候放的题,但是看完题后我就想,神TM树套树。

首先在树上查询一个点到另外一个点的信息很容易就想到树剖,但是至于怎么来维护剖出来的信息,首先明确题意,如果说风险度大于给定的c值那么也就是等价于查询从一个点到另外一个点之间在  当天-c 之前出现过那些点由于是动态维护的,所以很容易想到树状数组,我们以 i-c-1 从小到大排序,就可以保证在这个时间之前出现的点一定满足大于给定风险的。

1.但是一开始狂wa不止,感谢一个哥们的博客,就是在排序的时候一定要保证如果有修改操作,而且修改操作时间点和查询想通那么必须修改操作在前(我有加注释)

2.提醒在树状数组结合剖分的时候sum[a->top[a]]=sum[a]-sum[top[a]]+vis[top[a]]而不能用sum[a]-sum[fa[top[a]]]因为fa[top[a]]和top[a]不一定是在连续的区间

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 200010*3
#define maxm 200010*3
#include<algorithm>
using namespace std;
int n,m,top[maxn],dfn[maxn],fa[maxn],h[maxn],size[maxn],son[maxn],c[maxm],head[maxn*3],tot=1,rt,cnt,vis[maxn*3];
int ans1[maxn],ans2[maxn];
struct question{
int pos,x,y,c,begin,id;
bool operator<(const question& b)const{return begin==b.begin?pos==2:begin<b.begin ;}//恩 这里很关键
}q[maxn];
struct edge{
int v,next;
}e[maxn*3];
void adde(int a,int b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}

void dfs1(int u,int fa){
h[u]=h[fa]+1;size[u]=1;son[u]=0;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==fa)continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]])son[u]=v;
}
}
void dfs2(int u,int fa,int tt){
dfn[u]=++cnt;top[u]=tt;
if(son[u])dfs2(son[u],u,tt);
for(int i=head[u];~i;i=e[i].next ){
int v=e[i].v ;
if(v==fa||v==son[u])continue;
dfs2(v,u,v);
}
}
void updata(int x,int add){
while(x<=n*2){
c[x]+=add;
x+=(x&-x);
}
}
int query(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=(x&-x);
}
return ans;
}
int getlca(int x,int y){//!!!
while(top[x]!=top[y]){
if(h[top[x]]>h[top[y]])swap(x,y);
y=fa[top[y]];
}
return h[x]>h[y]?y:x;
}

int to_ans(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(h[top[x]]>h[top[y]])swap(x,y);

ans+=query(dfn[y])-query(dfn[top[y]])+vis[dfn[top[y]]];
y=fa[top[y]];
}
if(h[x]>h[y])swap(x,y);
ans+=query(dfn[y])-query(dfn[x])+vis[dfn[x]];
return ans;
}

int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",fa+i);
if(fa[i]==0)rt=i;
else adde(i,fa[i]),adde(fa[i],i);
}
dfs1(rt,rt);dfs2(rt,rt,rt);
scanf("%d",&m);
int ccnt=0;
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].pos ,&q[i].x );
if(q[i].pos == 2)q[i].begin=i;
else {
scanf("%d%d",&q[i].y ,&q[i].c);
q[i].begin = i-q[i].c-1;
q[i].id=++ccnt;
}
}
sort(q+1,q+1+m);

for(int i=1;i<=m;i++){
if(q[i].pos==2&&!vis[dfn[q[i].x]]){
vis[dfn[q[i].x]]=1;
updata(dfn[q[i].x],1);
}else{
int lca=getlca(q[i].x,q[i].y);
ans1[q[i].id]=h[q[i].x]+h[q[i].y]-2*h[lca]+1;
ans2[q[i].id]=to_ans(q[i].x,q[i].y);
}
}
for(int i=1;i<=ccnt;i++){
printf("%d %d\n",ans1[i],ans2[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: