BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树
题目描述
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个
部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。
每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部
门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光
缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行
数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的
交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况
。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通
信路径上延迟第k大的路由器的延迟时间。【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息
,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们
可能是: 1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。 2. 查
询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
输入
第一行为两个整数N和Q,分别表示路由器总数和询问的总数。
第二行有N个整数,第i个数表示编号为i的路由器初始的数据延迟时间Ti。
紧接着N-1行,每行包含两个整数x和y。表示有一条光缆连接路由器x和路由器y。
紧接着是Q行,每行三个整数k、a、b。
如果k=0,则表示路由器a的状态发生了变化,它的数据交换延迟时间由Ta变为b
如果k>0,则表示询问a到b的路径上所经过的所有路由器(包括a和b)中延迟
第k大的路由器的延迟时间。
注意N,Q<=80000,任意一个路由器在任何时刻都满足延迟时间小于10^8。
对于所有询问满足0<=K<=N
输出
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。
如果路径上的路由器不足k个,则输出信息“invalidrequest!”
(全部小写不包含引号,两个单词之间有一个空格)。
样例输入
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
样例输出
3
2
2
invalid request!
2
2
invalid request!
题目要求路径第k大,那么就要维护出路径每个点的权值。
我们不妨在树上每个点开一棵权值线段树来存这个点到根路径上每个点的权值。
查询时将路径以两点LCA分成两部分,即对于路径(x,y),只要将x点的线段树+y点的线段树-lca点的线段树-lca父节点的线段树就能得到路径上点的权值。
可以发现一个点的权值被子树内所有点上的线段树存储,在树上无法修改,那么可以转化到出栈入栈序上。
对于单点修改,在出栈入栈序上就是对于一个区间每个点的线段树都修改,而查询时是单点的线段树查询。
那么我们可以差分一下,在修改点入栈时刻加入出栈时刻删除,这样就变成了单点修改前缀查询。
直接树状数组套权值线段树即可。(套主席树和套权值线段树没啥区别,就是套权值线段树内存小点)
做这题之前建议先做->BZOJ1901
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; int s[80050]; int t[80050]; int num; int cnt; int tot; int a[80050]; int head[80050]; int to[160050]; int next[160050]; int sum[20000050]; int ls[20000050]; int rs[20000050]; int root[160050]; int f[80050]; int size[80010]; int top[80010]; int son[80010]; int d[80050]; int s1[80050]; int s2[80050]; int s3[80050]; int s4[80050]; int opt; int x,y; void addd(int x,int y) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; } void dfs2(int x,int t) { top[x]=t; if(son[x]) { dfs2(son[x],t); } for(int i=head[x];i;i=next[i]) { if(to[i]!=f[x]&&to[i]!=son[x]) { dfs2(to[i],to[i]); } } } int lca(int x,int y) { while(top[x]!=top[y]) { if(d[top[x]]>d[top[y]]) { swap(x,y); } y=f[top[y]]; } return d[x]<d[y]?x:y; } void updata(int &rt,int l,int r,int k,int v) { if(!rt) { rt=++cnt; } sum[rt]+=v; if(l==r) { return ; } int mid=(l+r)>>1; if(k<=mid) { updata(ls[rt],l,mid,k,v); } else { updata(rs[rt],mid+1,r,k,v); } } int query(int l,int r,int k) { if(l==r) { return l; } int res=0; for(int i=1;i<=s1[0];i++) { res+=sum[ls[s1[i]]]; } for(int i=1;i<=s2[0];i++) { res+=sum[ls[s2[i]]]; } for(int i=1;i<=s3[0];i++) { res-=sum[ls[s3[i]]]; } for(int i=1;i<=s4[0];i++) { res-=sum[ls[s4[i]]]; } int mid=(l+r)>>1; if(k<=res) { for(int i=1;i<=s1[0];i++) { s1[i]=ls[s1[i]]; } for(int i=1;i<=s2[0];i++) { s2[i]=ls[s2[i]]; } for(int i=1;i<=s3[0];i++) { s3[i]=ls[s3[i]]; } for(int i=1;i<=s4[0];i++) { s4[i]=ls[s4[i]]; } return query(l,mid,k); } else { for(int i=1;i<=s1[0];i++) { s1[i]=rs[s1[i]]; } for(int i=1;i<=s2[0];i++) { s2[i]=rs[s2[i]]; } for(int i=1;i<=s3[0];i++) { s3[i]=rs[s3[i]]; } for(int i=1;i<=s4[0];i++) { s4[i]=rs[s4[i]]; } return query(mid+1,r,k-res); } } void add(int k,int x,int v) { for(int i=x;i<=n;i+=i&(-i)) { updata(root[i],0,100000000,k,v); } } void ask(int x,int y,int k) { s1[0]=0; s2[0]=0; s3[0]=0; s4[0]=0; int anc=lca(x,y); for(int i=s[x];i;i-=i&(-i)) { s1[++s1[0]]=root[i]; } for(int i=s[y];i;i-=i&(-i)) { s2[++s2[0]]=root[i]; } for(int i=s[anc];i;i-=i&(-i)) { s3[++s3[0]]=root[i]; } if(f[anc]) { for(int i=s[f[anc]];i;i-=i&(-i)) { s4[++s4[0]]=root[i]; } } int len=d[x]+d[y]-d[anc]-d[f[anc]]; if(len<k) { printf("invalid request!\n"); } else { printf("%d\n",query(0,100000000,len-k+1)); } } void dfs(int x,int fa) { d[x]=d[fa]+1; f[x]=fa; size[x]=1; s[x]=++num; add(a[x],s[x],1); for(int i=head[x];i;i=next[i]) { if(to[i]!=fa) { dfs(to[i],x); size[x]+=size[to[i]]; if(size[to[i]]>size[son[x]]) { son[x]=to[i]; } } } t[x]=num+1; add(a[x],t[x],-1); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); addd(x,y); addd(y,x); } dfs(1,0); dfs2(1,1); for(int i=1;i<=m;i++) { scanf("%d%d%d",&opt,&x,&y); if(!opt) { add(a[x],s[x],-1); add(a[x],t[x],1); a[x]=y; add(a[x],s[x],1); add(a[x],t[x],-1); } else { ask(x,y,opt); } } }