• BZOJ 4448: [Scoi2015]情报传递


    题目:

    奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有n名情报员。每名情报员口J-能有
    若T名(可能没有)下线,除1名大头日外其余n-1名情报员有且仅有1名上线。奈特公司纪律森严,每
    名情报员只能与自己的上、下线联系,同时,情报网络中仟意两名情报员一定能够通过情报网络传递情报。
    奈特公司每天会派发以下两种任务中的一个任务:
    1.搜集情报:指派T号情报员搜集情报
    2.传递情报:将一条情报从X号情报员传递给Y号情报员
    情报员最初处于潜伏阶段,他们是相对安全的,我们认为此时所有情报员的危险值为0;-旦某个情报员开
    始搜集情报,他的危险值就会持续增加,每天增加1点危险值(开始搜集情报的当天危险值仍为0,第2天
    危险值为1,第3天危险值为2,以此类推)。传递情报并不会使情报员的危险值增加。
    为了保证传递情报的过程相对安全,每条情报都有一个风险控制值C。余特公司认为,参与传递这条情
    报的所有情报员中,危险值大于C的情报员将对该条情报构成威胁。现在,奈特公司希望知道,对于每
    个传递情报任务,参与传递的情报员有多少个,其中对该条情报构成威胁的情报员有多少个。
    题解:
    离线操作
    建一棵树上的主席树,以时间为关键字。
    代码:
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int tot,rt,T,cnt,last[1000005],ls[10000005],rs[10000005],tree[10000005],root[1000005],val[1000005],f[1000005][20],dep[1000005];
    struct node{
    	int to,next;
    }e[1000005];
    struct node1{
    	int x,y,z,ti;
    }q[1000005];
    void add(int a,int b){
    	e[++cnt].to=b;
    	e[cnt].next=last[a];
    	last[a]=cnt;
    }
    int lca(int x,int y){
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=19; i>=0; i--){
    		int to=f[x][i];
    		if (dep[to]>=dep[y]) x=to;
    	}
    	if (x==y) return x;
    	for (int i=19; i>=0; i--){
    		int fx=f[x][i],fy=f[y][i];
    		if (fx!=fy) x=fx,y=fy;
    	}
    	return f[x][0];
    }
    void dfs(int x,int fa){
    	f[x][0]=fa;
    	for (int i=0; i<19; i++) f[x][i+1]=f[f[x][i]][i];
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (V==fa) continue;
    		dep[V]=dep[x]+1;
    		dfs(V,x);
    	}
    }
    void insert(int &now,int pre,int l,int r,int x){
    	now=++cnt;
    	if (l==r){
    		tree[now]++;
    		return;
    	}
    	ls[now]=ls[pre],rs[now]=rs[pre];
    	int mid=(l+r)>>1;
    	if (x<=mid) insert(ls[now],ls[pre],l,mid,x);
    	else insert(rs[now],rs[pre],mid+1,r,x);
    	tree[now]=tree[ls[now]]+tree[rs[now]];
    }
    void solve(int x,int fa){
    	if (val[x]) insert(root[x],root[fa],1,T,val[x]);
    	else root[x]=root[fa];
    	for (int i=last[x]; i; i=e[i].next){
    		int V=e[i].to;
    		if (V==fa) continue;
    		solve(V,x);
    	}
    }
    int query(int now,int l,int r,int x){
    	if (!now) return 0;
    	x=min(x,r);
    	if (x<l) return 0;
    	if (l==r) return tree[now];
    	int mid=(l+r)>>1;
    	if (x>mid) return tree[ls[now]]+query(rs[now],mid+1,r,x);
    	else return query(ls[now],l,mid,x);
    }
    int main(){
    	int n;
    	scanf("%d",&n);
    	for (int i=1; i<=n; i++){
    		int x;
    		scanf("%d",&x);
    		if (x) add(x,i);
    		else rt=i;
    	}
    	dep[rt]=1;
    	dfs(rt,0);
    	cnt=0;
    	scanf("%d",&T);
    	for (int ti=1; ti<=T; ti++){
    		int k;
    		scanf("%d",&k);
    		if (k==1){
    			int x,y,z;
    			scanf("%d%d%d",&x,&y,&z);
    			q[++tot].x=x;
    			q[tot].y=y;
    			q[tot].z=ti-z-1;
    		}
    		else{
    			int x;
    			scanf("%d",&x);
    			val[x]=ti;
    		}
    	}
    	solve(rt,0);
    	for (int i=1; i<=tot; i++){
    		int x=q[i].x,y=q[i].y,z=q[i].z;
    		int LCA=lca(x,y);
    		int ans1=query(root[x],1,T,z);
    		int ans2=query(root[y],1,T,z);
    		int ans3=query(root[LCA],1,T,z);
    		int ans4=query(root[f[LCA][0]],1,T,z);
    		printf("%d %d
    ",dep[x]+dep[y]-dep[LCA]-dep[f[LCA][0]],ans1+ans2-ans3-ans4);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    centos 7 端口
    linux yum
    linux RPM包管理
    linux 进程
    linux 显示系统执行的进程
    linux 任务调度
    linux 组管理
    linux 压缩和解压缩
    linux 文件目录类的指令 包含查找
    PHP指定字段的多维数组排序方法
  • 原文地址:https://www.cnblogs.com/silenty/p/9351376.html
Copyright © 2020-2023  润新知