BZOJ 1146: [CTSC2008]网络管理Network 带修改主席树_树套树_DFS序
Description
M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门。为了让分布在世界各地的N个
部门之间协同工作,公司搭建了一个连接整个公司的通信网络。该网络的结构由N个路由器和N-1条高速光缆组成。
每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部
门进行通信联络。该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信。 高速光
缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略。但是由于路由器老化,在这些路由器上进行
数据交换会带来很大的延迟。而两个路由器之间的通信延迟时间则与这两个路由器通信路径上所有路由器中最大的
交换延迟时间有关。作为M公司网络部门的一名实习员工,现在要求你编写一个简单的程序来监视公司的网络状况
。该程序能够随时更新网络状况的变化信息(路由器数据交换延迟时间的变化),并且根据询问给出两个路由器通
信路径上延迟第k大的路由器的延迟时间。【任务】 你的程序从输入文件中读入N个路由器和N-1条光缆的连接信息
,每个路由器初始的数据交换延迟时间Ti,以及Q条询问(或状态改变)的信息。并依次处理这Q条询问信息,它们
可能是: 1. 由于更新了设备,或者设备出现新的故障,使得某个路由器的数据交换延迟时间发生了变化。 2. 查
询某两个路由器a和b之间的路径上延迟第k大的路由器的延迟时间。
Input
第一行为两个整数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
Output
对于每一个第二种询问(k>0),输出一行。包含一个整数为相应的延迟时间。
如果路径上的路由器不足k个,则输出信息“invalidrequest!”
(全部小写不包含引号,两个单词之间有一个空格)。
题解:
树套树.
之前做过不带修改的,感觉还挺容易的.
这次是带修改版本,就不能直接在树上建主席树了.
不同的是,我们对 $DFS$ 序建立主席树
考虑到每一次修改一个点,只会对该点的子树到根的路径产生影响.
在 DFS 序中,每个点的子树是一段连续的区间,直接用带修改主席树修改一波即可.
在 DFS 序中,每个点到根节点的路径和就是该点在 DFS 序中的前缀和.
这样进行修改和查询即可.
Code:
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
#define maxn 200000
#define N 180000
using namespace std;
int n,q, edges,cc,num;
//权值线段树
namespace Seg
{
#define mid ((l+r)>>1)
int rt[maxn],node[10][maxn],cnt[10];
int tot;
struct Node
{
int l,r,w;
}t[maxn*50];
void insert(int &x,int l,int r,int k,int delta)
{
if(!x) x=++tot;
t[x].w+=delta;
if(l==r) return;
if(k<=mid)
insert(t[x].l,l,mid,k,delta);
else
insert(t[x].r,mid+1,r,k,delta);
}
int lowbit(int t)
{
return t & (-t);
}
void update(int pos,int val,int delta)
{
while(pos<=N) insert(rt[pos],1,N,val,delta),pos+=lowbit(pos);
}
int query(int l,int r,int kth)
{
if(l==r) return l;
int sum=0;
for(int i=1;i<=cnt[0];++i) sum+=t[t[node[0][i]].r].w;
for(int i=1;i<=cnt[1];++i) sum+=t[t[node[1][i]].r].w;
for(int i=1;i<=cnt[2];++i) sum-=t[t[node[2][i]].r].w;
for(int i=1;i<=cnt[3];++i) sum-=t[t[node[3][i]].r].w;
if(sum < kth)
{
for(int i=1;i<=cnt[0];++i) node[0][i] = t[node[0][i]].l;
for(int i=1;i<=cnt[1];++i) node[1][i] = t[node[1][i]].l;
for(int i=1;i<=cnt[2];++i) node[2][i] = t[node[2][i]].l;
for(int i=1;i<=cnt[3];++i) node[3][i] = t[node[3][i]].l;
return query(l,mid,kth-sum);
}
else
{
for(int i=1;i<=cnt[0];++i) node[0][i] = t[node[0][i]].r;
for(int i=1;i<=cnt[1];++i) node[1][i] = t[node[1][i]].r;
for(int i=1;i<=cnt[2];++i) node[2][i] = t[node[2][i]].r;
for(int i=1;i<=cnt[3];++i) node[3][i] = t[node[3][i]].r;
return query(mid+1,r,kth);
}
}
// 关键字 : 位置
int Query(int a,int b,int c,int d,int kth)
{
cnt[0]=cnt[1]=cnt[2]=cnt[3]=0;
for(int i=a;i>0;i-=lowbit(i)) node[0][++cnt[0]] = rt[i];
for(int i=b;i>0;i-=lowbit(i)) node[1][++cnt[1]] = rt[i];
for(int i=c;i>0;i-=lowbit(i)) node[2][++cnt[2]] = rt[i];
for(int i=d;i>0;i-=lowbit(i)) node[3][++cnt[3]] = rt[i];
return query(1,N,kth);
}
};
struct Query
{
int opt,a,b;
}Q[maxn];
int hd[maxn],to[maxn],nex[maxn],dfs[maxn],arr[maxn],A[maxn];
int st[maxn],ed[maxn],F[20][maxn],dep[maxn],val[maxn];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
//read and diskreat
void read()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) scanf("%d",&val[i]),A[++cc]=val[i];
for(int i=1,a,b;i<n;++i)
scanf("%d%d",&a,&b), add(a,b),add(b,a);
for(int i=1;i<=q;++i)
{
scanf("%d%d%d",&Q[i].opt,&Q[i].a,&Q[i].b);
if(Q[i].opt==0) A[++cc]=Q[i].b;
}
sort(A+1,A+1+cc);
for(int i=1;i<=q;++i) if(Q[i].opt==0) Q[i].b=lower_bound(A+1,A+1+cc,Q[i].b)-A;
for(int i=1;i<=n;++i) val[i] = lower_bound(A+1,A+1+cc,val[i])-A;
}
//求dfs序
void DFS(int u,int fa)
{
F[0][u]=fa, dep[u] = dep[fa] + 1;
for(int i=1;i<20;++i) F[i][u]=F[i-1][F[i-1][u]];
dfs[++num]=val[u],st[u]=num;
for(int i=hd[u];i;i=nex[i])
{
if(to[i]==fa) continue;
DFS(to[i],u);
}
ed[u]=num+1;
}
int LCA(int a,int b)
{
if(dep[b]<dep[a]) swap(a,b);
if(dep[a]!=dep[b])
{
for(int i=19;i>=0;--i) if(dep[F[i][b]] >= dep[a]) b = F[i][b];
}
if(a==b) return a;
for(int i=19;i>=0;--i)
{
if(F[i][a]!=F[i][b]) a = F[i][a], b = F[i][b];
}
return F[0][a];
}
int main()
{
// setIO("input");
read();
DFS(1,0);
for(int i = 1;i <= n; ++i)
{
Seg::update(st[i],val[i], 1);
Seg::update(ed[i],val[i], -1);
}
for(int i=1,a,b;i<=q;++i)
{
a = Q[i].a, b = Q[i].b;
if(Q[i].opt==0)
{
Seg::update(st[a], val[a], -1);
Seg::update(ed[a], val[a], 1);
val[a] = b;
Seg::update(st[a],val[a], 1);
Seg::update(ed[a],val[a], -1);
}
if(Q[i].opt>0)
{
int lca = LCA(a,b);
int c = Seg::Query(st[a],st[b],st[lca],st[F[0][lca]],Q[i].opt);
if(c==1)
printf("invalid request!\n");
else
printf("%d\n",A[c]);
}
}
return 0;
}