P4216 [SCOI2015] 情报传递

P4216 [SCOI2015] 情报传递

题意简述:给你一棵树,在每个时刻可能将某个点点亮,或者做一次查询,询问x->y路径上有多少点是在当前时间k秒前点亮的

Solution:

这让我们很难不想到主席树:

每个节点建一颗主席树,维护根节点到此节点路径上在某个时间段内被点亮的点的个数(即以时间为x轴,点的个数为权值建树)

然后将所有操作离线,按照从浅到深(先父后子)建立主席树,然后对于每次查询(x,y)查询
t[x]+t[y]-t[lca]-t[fa_lca]这颗主席树上在[1,i-k-1]
(原题的k是不被包含的,但我线段树维护的闭区间)

然后这题就做完了
疑似我写过的最短紫题总结

Code:

#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
struct Tree{
int ls,rs,num;
}t[N*80];
int n,m,cnt,tot;
void insert(int &x,int y,int l,int r,int val)
{
t[x=++cnt]=t[y];
t[x].num++;
if(l==r)
{
return ;
}
int mid=l+r>>1;
if(val<=mid)insert(t[x].ls,t[y].ls,l,mid,val);
if(mid<val) insert(t[x].rs,t[y].rs,mid+1,r,val);
}
void query(int x,int y,int lca,int lca_fa,int l,int r,int L,int R,int &res)
{
if(R<l||r<L)return;
if(L<=l&&r<=R)
{
res+=t[x].num+t[y].num-t[lca].num-t[lca_fa].num;
return ;
}
int mid=l+r>>1;
if(L<=mid) query(t[x].ls,t[y].ls,t[lca].ls,t[lca_fa].ls,l,mid,L,R,res);
if(mid<R)query(t[x].rs,t[y].rs,t[lca].rs,t[lca_fa].rs,mid+1,r,L,R,res);
}
int dep[N],fa[N][25],rt[N],tim[N];
vector<int> E[N];
void dfs(int x,int f)
{
dep[x]=dep[f]+1;
fa[x][0]=f;
if(tim[x])insert(rt[x],rt[f],1,m,tim[x]);
else rt[x]=rt[f];
for(int i=1;i<=20;i++)
{
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=0;i<E[x].size();i++)
{
int to=E[x][i];
if(to==f)continue;
dfs(to,x);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=20;~i;i--)
{
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(int i=20;~i;i--)
{
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
struct task{
int opt,x,y,k;
}q[N];
struct add{
int x,tim,dep;
bool operator<(const add &a)const{
return dep<a.dep;
}
}e[N];
void work()
{
cin>>n;
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
E[x].push_back(i);
E[i].push_back(x);
}
cin>>m;
for(int i=1,opt,x,y,k;i<=m;i++)
{
scanf("%d%d",&opt,&x);
if(opt==1)
{
scanf("%d%d",&y,&k);
}
else
{
tim[x]=i;
}
q[i]=(task){opt,x,y,k};
}
dfs(1,0);
for(int i=1,x,y,k;i<=m;i++)
{
if(q[i].opt==1)
{
x=q[i].x,y=q[i].y,k=q[i].k+1;
int lca=LCA(x,y),ans=0; query(rt[x],rt[y],rt[lca],rt[fa[lca][0]],1,m,1,i-k,ans);
printf("%d %d\n",dep[x]+dep[y]-dep[lca]*2+1,ans);
}
}
return ;
}
int main()
{
//freopen("P4216.in","r",stdin);freopen("P4216.out","r",stdout);
work();
return 0;
}
posted @   liuboom  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示