1. 程式人生 > >BZOJ4448: [Scoi2015]情報傳遞

BZOJ4448: [Scoi2015]情報傳遞

sam 起點 空行 行數 push_back 一行 pan pda time

題解:離線把所以修改操作對應到樹上每個節點的權值即可 問題轉化成查詢一條路徑上的小於某個值的個數 主席樹即可

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=2e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}


int fa[MAXN][21],dep[MAXN],vis[MAXN],cnt,rt[MAXN],n,q;
typedef struct node{
	int l,r,sum;
}node;
node d[MAXN*21];
void update(int &x,int y,int l,int r,int t){
	x=++cnt;d[x]=d[y];d[x].sum++;
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(t<=mid)update(d[x].l,d[y].l,l,mid,t);
	else update(d[x].r,d[y].r,mid+1,r,t);
}
int ans;
int Lca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	int tmp=dep[u]-dep[v];
	for(int i=0;i<=20;i++)if(tmp&(1<<i))u=fa[u][i];
	if(u==v)return u;
	for(int i=20;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];v=fa[v][i];
		}
	}
	return fa[u][0];
}
void querty(int x,int y,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr){ans+=d[y].sum-d[x].sum;return ;}
	int mid=(l+r)>>1;
	if(ql<=mid)querty(d[x].l,d[y].l,l,mid,ql,qr);
	if(qr>mid)querty(d[x].r,d[y].r,mid+1,r,ql,qr);
}
void dfs(int x,int f,int deep){
	fa[x][0]=f;dep[x]=deep+1;
	link(x)if(j->t!=f)dfs(j->t,x,deep+1);
}
void dfs1(int x){
	inc(i,1,20)fa[x][i]=fa[fa[x][i-1]][i-1];
	if(vis[x])update(rt[x],rt[fa[x][0]],1,n,vis[x]);
	else rt[x]=rt[fa[x][0]];
	link(x)if(j->t!=fa[x][0])dfs1(j->t);
}
typedef struct Q{
	int u,v,c,id;
}Q;
Q que[MAXN];
int main(){
	n=read();int pos,u,v;
	inc(i,1,n){
		u=read(),add(u,i),add(i,u);
		if(!u)pos=i;
	}
	q=read();int cnt1=0,op;
	inc(i,1,q){
		op=read();
		if(op==1)que[++cnt1].u=read(),que[cnt1].v=read(),que[cnt1].c=read(),que[cnt1].id=i;
		else {
			u=read();
			if(!vis[u])vis[u]=i;
		}
	}
	dfs(pos,0,0);dfs1(pos);
	inc(i,1,cnt1){
		int lca=Lca(que[i].u,que[i].v);
		int sum=0;
		if(que[i].id-que[i].c>1)ans=0,querty(rt[lca],rt[que[i].u],1,n,1,que[i].id-que[i].c-1),sum+=ans;
		if(que[i].id-que[i].c>1)ans=0,querty(rt[lca],rt[que[i].v],1,n,1,que[i].id-que[i].c-1),sum+=ans;
		if(vis[lca]&&que[i].id-vis[lca]>=que[i].c)sum++;
		printf("%d %d\n",dep[que[i].u]+dep[que[i].v]-2*dep[lca]+1,sum);
	}
	return 0;
}

  

4448: [Scoi2015]情報傳遞

Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 1129 Solved: 603
[Submit][Status][Discuss]

Description

奈特公司是一個巨大的情報公司,它有著龐大的情報網絡。情報網絡中共有n名情報員。每名情報員口J-能有 若T名(可能沒有)下線,除1名大頭日外其余n-1名情報員有且僅有1名上線。奈特公司紀律森嚴,每 名情報員只能與自己的上、下線聯系,同時,情報網絡中仟意兩名情報員一定能夠通過情報網絡傳遞情報。 奈特公司每天會派發以下兩種任務中的一個任務: 1.搜集情報:指派T號情報員搜集情報 2.傳遞情報:將一條情報從X號情報員傳遞給Y號情報員 情報員最初處於潛伏階段,他們是相對安全的,我們認為此時所有情報員的危險值為0;-旦某個情報員開 始搜集情報,他的危險值就會持續增加,每天增加1點危險值(開始搜集情報的當天危險值仍為0,第2天 危險值為1,第3天危險值為2,以此類推)。傳遞情報並不會使情報員的危險值增加。 為了保證傳遞情報的過程相對安全,每條情報都有一個風險控制值C。余特公司認為,參與傳遞這條情 報的所有情報員中,危險值大於C的情報員將對該條情報構成威脅。現在,奈特公司希望知道,對於每 個傳遞情報任務,參與傳遞的情報員有多少個,其中對該條情報構成威脅的情報員有多少個。

Input

第1行包含1個正整數n,表示情報員個數。 笫2行包含n個非負整數,其中第i個整數Pi表示i號情報員上線的編號。特別地,若Pi=0,表示i號 情報員是大頭目。 第3行包含1個正整數q,表示奈特公司將派發q個任務(每天一個)。 隨後q行,依次描述q個任務。 每行首先有1個正整數k。若k=1,表示任務是傳遞情報,隨後有3個正整數Xi、Yi、Ci,依次表示傳遞 情報的起點、終點和風險控制值;若k=2,表示任務是搜集情報,隨後有1個正整數Ti,表示搜集情報的 情報員編號。

Output

對於每個傳遞情報任務輸出一行,應包含兩個整數,分別是參與傳遞情報的情報員個數和對該條情報構成威脅的情報員個數。 輸出的行數應等於傳遞情報任務的個數,每行僅包含兩個整數,用一個空格隔開。輸出不應包含多余的空行和空格。

Sample Input

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


Sample Output

5 0
5 2
5 1

BZOJ4448: [Scoi2015]情報傳遞