题解:离线把所以修改操作对应到树上每个节点的权值即可 问题转化成查询一条路径上的小于某个值的个数 主席树即可
#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 ",dep[que[i].u]+dep[que[i].v]-2*dep[lca]+1,sum); } return 0; }
4448: [Scoi2015]情报传递
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 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
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
5 2
5 1