[BZOJ]4448: [Scoi2015]情报传递 主席树+LCA

来源:互联网 发布:java车辆管理系统源码 编辑:程序博客网 时间:2024/06/05 19:02

Description
奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有n名情报员。每名情报员口J-能有若T名(可能没有)下线,除1名大头日外其余n-1名情报员有且仅有1名上线。奈特公司纪律森严,每名情报员只能与自己的上、下线联系,同时,情报网络中仟意两名情报员一定能够通过情报网络传递情报。奈特公司每天会派发以下两种任务中的一个任务:
1.搜集情报:指派T号情报员搜集情报
2.传递情报:将一条情报从X号情报员传递给Y号情报员
情报员最初处于潜伏阶段,他们是相对安全的,我们认为此时所有情报员的危险值为0;-旦某个情报员开始搜集情报,他的危险值就会持续增加,每天增加1点危险值(开始搜集情报的当天危险值仍为0,第2天危险值为1,第3天危险值为2,以此类推)。传递情报并不会使情报员的危险值增加。为了保证传递情报的过程相对安全,每条情报都有一个风险控制值C。余特公司认为,参与传递这条情报的所有情报员中,危险值大于C的情报员将对该条情报构成威胁。现在,奈特公司希望知道,对于每个传递情报任务,参与传递的情报员有多少个,其中对该条情报构成威胁的情报员有多少个。

题解:

离线乱搞,搜集情报的话就把那个点赋值为当前是第几次询问,传递情报的话第一问就LCA,第二问就找路径上有多少个权值小于等于i-q[i].c-1的点,这个自己想想很快就明白了,至于如何找,就用主席树,每个点一颗树维护当前点到根上的信息,乱搞搞就好了。

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;const int maxn=200010;struct Edge{int y,next;}e[maxn];int len=0,last[maxn];int dep[maxn],fa[maxn][20];int lc[maxn*25],rc[maxn*25],s[maxn*25],root[maxn],cnt=0,o[maxn];void ins(int x,int y){    int t=++len;    e[t].y=y;e[t].next=last[x];last[x]=t;}int n,Q,Root;void ins(int &u,int l,int r,int p){    if(!u)u=++cnt;    s[u]++;    if(l==r)return;    int mid=l+r>>1;    if(p<=mid)ins(lc[u],l,mid,p);    else ins(rc[u],mid+1,r,p);}void merge(int &u1,int u2){    if(!u1){u1=u2;return;}    if(!u2)return;    s[u1]+=s[u2];    merge(lc[u1],lc[u2]);    merge(rc[u1],rc[u2]);}void dfs(int x){    for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];    if(o[x])ins(root[x],1,Q,o[x]);    merge(root[x],root[fa[x][0]]);    for(int i=last[x];i;i=e[i].next)    {        int y=e[i].y;        fa[y][0]=x;dep[y]=dep[x]+1;        dfs(y);    }}int lca(int x,int y){    if(dep[x]<dep[y])swap(x,y);    for(int i=18;i>=0;i--)    if((1<<i)<=dep[x]-dep[y])x=fa[x][i];    if(x==y)return x;    for(int i=18;i>=0;i--)    if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i])    x=fa[x][i],y=fa[y][i];    return fa[x][0];}struct Ask{int op,x,y,c;}q[maxn];int query(int rt1,int rt2,int rt3,int rt4,int l,int r,int k){    int mid=l+r>>1,c=s[lc[rt3]]+s[lc[rt4]]-s[lc[rt1]]-s[lc[rt2]];    if(l==r)    {        if(l<=k)return s[rt3]+s[rt4]-s[rt1]-s[rt2];        else return 0;    }    if(k<=mid)return query(lc[rt1],lc[rt2],lc[rt3],lc[rt4],l,mid,k);    else return c+query(rc[rt1],rc[rt2],rc[rt3],rc[rt4],mid+1,r,k);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        int x;        scanf("%d",&x);        if(!x)Root=i;        else ins(x,i);    }    scanf("%d",&Q);    for(int i=1;i<=Q;i++)    {        scanf("%d%d",&q[i].op,&q[i].x);        if(q[i].op==1)scanf("%d%d",&q[i].y,&q[i].c);        else o[q[i].x]=i;    }    dep[Root]=1;fa[Root][0]=0;dfs(Root);    for(int i=1;i<=Q;i++)    if(q[i].op==1)    {        int g=lca(q[i].x,q[i].y);        printf("%d ",dep[q[i].x]+dep[q[i].y]-2*dep[g]+1);        printf("%d\n",query(root[g],root[fa[g][0]],root[q[i].x],root[q[i].y],1,Q,i-q[i].c-1));    }}