BZOJ 4448: [Scoi2015]情报传递 树链剖分 主席树
2016-05-04 21:08
381 查看
4448: [Scoi2015]情报传递
题目连接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4448Description
奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有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
70 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 05 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
题意
题解:
离线之后,把2操作全部更新之后1操作就变成查询链(x,y)上面,有多少个小于等于i-c[i]-1就完了
这个智障题就熟练剖分+主席树莽一波好啦
代码
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5+7; 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; } vector<int>E[maxn]; int n,m,cnt,l[maxn*20],r[maxn*20],fa[maxn],top[maxn],sz[maxn],deep[maxn],id[maxn],son[maxn],root[maxn*20],sum[maxn*20],x[maxn],y[maxn],c[maxn],op,cnt2,t[maxn],rh[maxn]; void add(int x,int y) { if(x==0||y==0)return; E[x].push_back(y); E[y].push_back(x); } void dfs(int x,int f) { sz[x]=1;fa[x]=f; for(int i=0;i<E[x].size();i++) { int v=E[x][i]; if(v==f)continue; deep[v]=deep[x]+1; dfs(v,x); sz[x]+=sz[v]; if(sz[v]>sz[son[x]])son[x]=v; } } void dfs2(int x,int f) { id[x]=++cnt;top[x]=f;rh[cnt]=x; if(son[x])dfs2(son[x],f); for(int i=0;i<E[x].size();i++) { int v=E[x][i]; if(v==fa[x]||v==son[x])continue; dfs2(v,v); } } void update(int pre,int &x,int ll,int rr,int v) { x=++cnt;l[x]=l[pre],r[x]=r[pre];sum[x]=sum[pre]+1; if(ll==rr)return; int mid=ll+rr>>1; if(v<=mid)update(l[pre],l[x],ll,mid,v); else update(r[pre],r[x],mid+1,rr,v); } int query(int x,int y,int c) { int L=root[x-1],R=root[y],ll=1,rr=m,res=0; while(ll!=rr) { int mid=ll+rr>>1; if(c<=mid)L=l[L],R=l[R],rr=mid; else res+=sum[l[R]]-sum[l[L]],L=r[L],R=r[R],ll=mid+1; } res+=(c>=ll?sum[R]-sum[L]:0); return res; } void solve(int x,int y,int c) { int ans=0;int tmp=deep[x]+deep[y]; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]])swap(x,y); ans+=query(id[top[x]],id[x],c);x=fa[top[x]]; } if(deep[x]<deep[y])swap(x,y); ans+=query(id[y],id[x],c); printf("%d %d\n",tmp-2*deep[y]+1,ans); } int main() { n=read(); for(int i=1;i<=n;i++)add(read(),i); dfs(1,1);dfs2(1,1); m=read(); for(int i=1;i<=n;i++)t[i]=m; for(int i=1;i<=m;i++) { if(read()==1)x[cnt2]=read(),y[cnt2]=read(),c[cnt2++]=i-read()-1; else t[read()]=i; } for(int i=1;i<=n;i++)update(root[i-1],root[i],1,m,t[rh[i]]); for(int i=0;i<cnt2;i++)solve(x[i],y[i],c[i]); }
相关文章推荐
- 无重边无向连通图的割点和桥
- NIO边看边记 之 Scatter/Gather(四)
- C++基础实例-类(6)
- SDAU dp专题 1002
- [python]迭代器与生成器
- Java学习笔记之反射
- 疯狂安卓书籍的学习--未完待续~
- java项目转为web项目
- MSP430 SD16_A的采样速率的研究
- Nginx和Tengine
- 项目遇到R文件无法自动生成的解决
- web学习笔记-httpServletResponse一
- 51Nod-算法马拉松13-A-取余最长路
- C++短信接口快速入门
- cf339d Xenia and Bit Operations
- 算法性能评价
- 动态规划初学
- WebBasic05-JS
- 函数指针
- python 和 nodejs 比较