博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[SCOI2015]情报传递(主席树+lca)
阅读量:4134 次
发布时间:2019-05-25

本文共 2783 字,大约阅读时间需要 9 分钟。

链接:https://ac.nowcoder.com/acm/problem/20570

来源:牛客网
在这里插入图片描述
输出描述:
对于每个传递情报任务输出一行,应包含两个整数,分别是参与传递情报的情报员个数和对该条情报构成威胁的情报员个数。
输出的行数应等于传递情报任务的个数,每行仅包含两个整数,用一个空格隔开。输出不应包含多余的空行和空格。
示例1
输入
复制
7
0 1 1 2 2 3 3
6
1 4 7 0
2 1
2 4
2 7
1 4 7 1
1 4 7 3
输出
复制
5 0
5 2
5 1
在线转离线挺巧妙的一道题目。对于搜集情报的队员来说,从唤醒它的那一刻起,到询问的时候,它的风险控制值怎么算呢?而且如果强制在线做的话,每一天之后,搜索情报的队员的风险控制值就会改变,这样很麻烦。每个队员的风险控制值和询问时候的时间怎么算呢?对于每个询问的时候,在i-c-1秒之前就唤醒的队员的风险控制值就一定会有风险。这样的话,我们把所有的操作离线,然后对于唤醒队员操作,就是给每个队员赋值为val[i]=唤醒它的这个时间。离线操作完了之后,就按着dfs序建立主席树。查询的时候,对于点权来说,根据树上差分,返回sum[x]+sum[y]-sum[lca(x,y)]-sum[fa[lca(x,y)]]。
具体解释看代码:

#include
#define ll long longusing namespace std;const int maxx=2e5+100;struct node{
int l; int r; int num;}p[maxx*40];struct edge{
int to,next;}e[maxx<<1];struct ddd{
int x,y,t;}q[maxx];int head[maxx<<1],dp[maxx][26];int root[maxx],deep[maxx],val[maxx];int n,m,tot,rt,ror;/*------------事前准备-------------*/inline void init(){
memset(dp,0,sizeof(dp)); memset(val,0,sizeof(val)); memset(head,-1,sizeof(head)); tot=ror=0;}inline void add(int u,int v){
e[tot].to=v,e[tot].next=head[u],head[u]=tot++;}/*----------主席树-----------*/inline int build(int l,int r){
int cur=++ror; p[cur].num=0; if(l==r) return cur; int mid=l+r>>1; p[cur].l=build(l,mid); p[cur].r=build(mid+1,r); return cur;}inline int update(int rot,int l,int r,int pos){
int cur=++ror; p[cur]=p[rot]; p[cur].num++; if(l==r) return cur; int mid=l+r>>1; if(pos<=mid) p[cur].l=update(p[rot].l,l,mid,pos); else p[cur].r=update(p[rot].r,mid+1,r,pos); return cur;}inline int query(int lrot,int rrot,int frot,int ffrot,int l,int r,int pos){
if(l>pos) return 0; if(r<=pos) return p[lrot].num+p[rrot].num-p[frot].num-p[ffrot].num;//点差分 int mid=l+r>>1; int ret=0; if(pos>=l) ret+=query(p[lrot].l,p[rrot].l,p[frot].l,p[ffrot].l,l,mid,pos); if(pos>mid) ret+=query(p[lrot].r,p[rrot].r,p[frot].r,p[ffrot].r,mid+1,r,pos); return ret;}/*------------dfs------------*/inline void dfs(int u,int f){
deep[u]=deep[f]+1; dp[u][0]=f; for(int i=1;i<=25;i++) {
if(dp[u][i-1]) dp[u][i]=dp[dp[u][i-1]][i-1]; else break; } root[u]=update(root[f],1,m,val[u]); for(int i=head[u];i!=-1;i=e[i].next) {
int to=e[i].to; if(to==f) continue; dfs(to,u); }}/*-----------lca-----------*/inline int get_lca(int x,int y){
if(deep[x]
=0;i--) {
if(dp[x][i]!=dp[y][i]) {
x=dp[x][i]; y=dp[y][i]; } } return dp[x][0];}int main(){
init();int x,op,y,c; scanf("%d",&n); for(int i=1;i<=n;i++) {
scanf("%d",&x); if(x==0) rt=i; add(x,i);add(i,x); } scanf("%d",&m); for(int i=1;i<=n;i++) val[i]=m;//因为转化之后求得是小于等于某个值的数,所以初始化就要设置为最大值 int cnt=0; for(int i=1;i<=m;i++) {
scanf("%d",&op); if(op==1) {
scanf("%d%d%d",&x,&y,&c); q[++cnt].x=x,q[cnt].y=y,q[cnt].t=i-c-1;//将所有查询操作保存下来。 } else {
scanf("%d",&x); val[x]=i; } } root[0]=build(1,m); deep[0]=0; dfs(rt,0); for(int i=1;i<=cnt;i++) {
x=q[i].x,y=q[i].y,c=q[i].t; int Lca=get_lca(x,y); printf("%d ",deep[x]+deep[y]-2*deep[Lca]+1);//节点个数。 printf("%d\n",query(root[x],root[y],root[Lca],root[dp[Lca][0]],1,m,c)); } return 0;}

努力加油a啊,(o)/~

转载地址:http://zytvi.baihongyu.com/

你可能感兴趣的文章