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\n",dep[x]+dep[y]-dep[LCA]-dep[f[LCA][0]],ans1+ans2-ans3-ans4);
	}
	return 0;
}

  

posted @ 2018-07-22 20:50  ~Silent  阅读(180)  评论(0编辑  收藏  举报
Live2D