BZOJ4448: [Scoi2015]情報傳遞(主席樹)
BZOJ4448: [Scoi2015]情報傳遞
Time Limit: 20 Sec
Memory Limit: 256 MBDescription
奈特公司是一個巨大的情報公司,它有著龐大的情報網絡。情報網絡中共有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
HINT
對於3個傳遞情報任務,都是經過5名情報員,分別是4號、2號、1號、3號和7號。其中,對於第1個任務,所有情報員(危險值為0)都不對情報構成威脅;對於第2個任務,有2名情報員對情報構成威脅,分別是1號情報員(危險值為3)和4號情報員(危險值為2),7號情報員(危險值為1)並不構成威脅;對於第3個任務,只有1名情報員對情報構成威脅。
n< = 2×10^5,Q< = 2×105,0< Pi,C!< = N, 1< = Ti,Xi,Yi< = n
題解:JudgeOnline/upload/201603/Solution-4448.rar
題目地址:BZOJ4448: [Scoi2015]情報傳遞
題目大意:
維護一顆樹,支持以下操作(可以離線)
1、給一個點賦值;
2、查詢一條鏈上比k大的點有多個
題解:
樹上做主席樹的套路
對於每一個節點,把它們到根路徑上的所有點權建一顆權值線段樹
對於一個節點 \(u\) 和他的父親 \(fa\)
他們兩個的權值線段樹只改變了一個數\((u)\) 用主席樹維護(套路)
對於這道題,我們只要離線把所有賦值都賦好
對於每次查詢 \(L,R\)
我們找出他們的最近公共祖先 \(Fa=lca(L,R)\) 和最近公共祖先的父親 \(Gr=fa[Fa]\)
第一問只要輸出 \(dep[L[i]]+dep[R[i]]-dep[Fa]-dep[Gr]\) 就行了
第二問只要輸出 \(solve(L)+solve(R)-solve(Fa)-solve(Gr)\)
具體證明可以畫畫圖或歐拉序推出
套路啊
類似題目 Count on a tree
AC代碼
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=2e5+5,M=4e6;
int n,m,rt;
int res_1,res_2,res_3,res_4;
int op[N],L[N],R[N],K[N],vis[N];
int T[M],root[M],son[M][2],fa[N][19];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct edge{
int to,next;
}e[N+N];
int cnt,last[N];
void add_edge(int u,int v){
e[++cnt]=(edge){v,last[u]};last[u]=cnt;
e[++cnt]=(edge){u,last[v]};last[v]=cnt;
}
int Time,pos[N],dep[N];
void dfs(int u,int father){
pos[++Time]=u;
dep[u]=dep[father]+1;
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==father)continue;
fa[v][0]=u;
dfs(v,u);
}
}
int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
for(int i=18;i>=0;i--)
if(dep[fa[a][i]]>=dep[b])
a=fa[a][i];
if(a==b)return a;
for(int i=18;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int Knum;
void change(int &now,int l,int r,int k){
Knum++;
T[Knum]=T[now]+1;
son[Knum][0]=son[now][0];
son[Knum][1]=son[now][1];
now=Knum;
if(l==r)return;
int mid=(l+r)>>1;
if(k<=mid)change(son[now][0],l,mid,k);
else change(son[now][1],mid+1,r,k);
}
int query(int now,int l,int r,int L,int R){
if(L>R)return 0;
if(L<=l && r<=R)return T[now];
int mid=(l+r)>>1,res=0;
if(L<=mid)res+=query(son[now][0],l,mid,L,R);
if(R>mid)res+=query(son[now][1],mid+1,r,L,R);
return res;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int fa=read();
if(fa==0)rt=i;
else add_edge(fa,i);
}
dfs(rt,0);
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
m=read();
for(int i=1;i<=m;i++){
op[i]=read();
if(op[i]==1)L[i]=read(),R[i]=read(),K[i]=read();
else{
int x=read();
vis[x]=i;
}
}
for(int i=1;i<=n;i++){
root[pos[i]]=root[fa[pos[i]][0]];
if(vis[pos[i]])
change(root[pos[i]],1,m,vis[pos[i]]);
}
for(int i=1;i<=m;i++)
if(op[i]==1){
int Fa=lca(L[i],R[i]),Gr=fa[Fa][0];
int k=i-K[i]-1;
res_1=query(root[L[i]],1,m,1,k);
res_2=query(root[R[i]],1,m,1,k);
res_3=query(root[Fa],1,m,1,k);
if(Gr)res_4=query(root[Gr],1,m,1,k);
else res_4=0;
printf("%d %d\n",dep[L[i]]+dep[R[i]]-dep[Fa]-dep[Gr],res_1+res_2-res_3-res_4);
}
return 0;
}
作者:skl_win
出處:https://www.cnblogs.com/shaokele/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
BZOJ4448: [Scoi2015]情報傳遞(主席樹)