BZOJ1146: [CTSC2008]网络管理Network
Description
Input
Output
Sample Input
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
Sample Output
2
2
invalid request!
经典的带修树链第k大问题。
然而一开始敲成了第k小,尴尬。。。
先说说几种可行的方法:
-
大力树套树+树链剖分,复杂度 O(nlog4n) 比较吓人,我一开始打出来就吓一跳,说这怎么可能过?但是真的妥妥的AC 100 ,我也是醉了。。。
-
树链剖分+树状数组套主席树,复杂度 O(nlog3n) ,有点吓人。。。
主席树天生就可以直接求第k大而不用像平衡树那样二分答案。
看似平衡树可以直接求第k大,实际上这样没法合并多棵平衡树的答案,必须得二分,而主席树不用。
-
dfs序+树状数组套主席树,复杂度 O(nlog2n) ,能过。
-
最后一种,也是最强的一种,复杂度 O(nlogn) ,不过我不会。。。
这里讲第3种。
先考虑没有修改怎么做:
树上第k大,主席树存某节点到根节点的前缀和,查询是这么弄:
int query(int u,int v,int f,int gf,int k,int l,int r){
if(l==r)return l;
int mid=l+r>>1,t=a[a[u].l].sum+a[a[v].l].sum-a[a[f].l].sum-a[a[gf].l].sum;
if(k<=t)return query(a[u].l,a[v].l,a[f].l,a[gf].l,k,l,mid);
else return query(a[u].r,a[v].r,a[f].r,a[gf].r,k-t,mid+1,r);
}
这样就可以了。
但是有修改,怎么办?
我们想起序列上的带修改第k大,可以用树状数组套主席树!
那么怎么转换到树上呢?
树链剖分!
但是很明显,树剖需要对原树重新编号,会很烦人(我表示我很懒)。
所以就用了另外一个跟树剖很像但是更简单(功能也更弱)的dfs序!
然后把所有的主席树进行差分,差分后每棵主席树每个位置的值相当于原来它这个位置的值-原来它在dfs序上的前一棵主席树这个位置的值。
修改时就是把区间修改转化成两个单点修改,查询时一次性查询4条链对应的前缀主席树。
注:记得开大数组!记得开大数组!记得开大数组!
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 80010
using namespace std;
int n,m,K,c=1,d=0;
int val[MAXN],num[MAXN<<1],root[MAXN];
int head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],front[MAXN],next[MAXN],top[MAXN];
struct Tree{
int next,to;
}a[MAXN<<1];
struct Question{
int k,x,y;
}que[MAXN];
struct Binary_Indexed_Tree{
int size,id[50];
}bit_one,bit_two;
inline int read(){
int date=0,w=1;char last=0,c=0;
while(c<'0'||c>'9'){last=c;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
if(last=='-')w=-1;
return date*w;
}
namespace ST{
int size=0;
struct Segment_Tree{
int sum,l,r;
}a[MAXN*125];
inline void buildtree(){
a[0].l=a[0].r=a[0].sum=root[0]=0;
}
void insert(int k,int v,int l,int r,int &rt){
if(!rt)rt=++size;
a[rt].sum+=v;
if(l==r)return;
int mid=l+r>>1;
if(k<=mid)insert(k,v,l,mid,a[rt].l);
else insert(k,v,mid+1,r,a[rt].r);
}
int query(int l,int r,int k){
if(l==r)return l;
int mid=l+r>>1,t=0;
for(int i=1;i<=bit_one.size;i++)t+=a[a[bit_one.id[i]].l].sum;
for(int i=1;i<=bit_two.size;i++)t-=a[a[bit_two.id[i]].l].sum;
if(k<=t){
for(int i=1;i<=bit_one.size;i++)bit_one.id[i]=a[bit_one.id[i]].l;
for(int i=1;i<=bit_two.size;i++)bit_two.id[i]=a[bit_two.id[i]].l;
return query(l,mid,k);
}
else{
for(int i=1;i<=bit_one.size;i++)bit_one.id[i]=a[bit_one.id[i]].r;
for(int i=1;i<=bit_two.size;i++)bit_two.id[i]=a[bit_two.id[i]].r;
return query(mid+1,r,k-t);
}
}
}
inline void add(int x,int y){
a[c].to=y;a[c].next=head[x];head[x]=c++;
a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;front[rt]=++d;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
next[rt]=d;
}
void dfs2(int rt,int f){
top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
inline int lowbit(int x){return x&(-x);}
inline void update(int x,int v,int w){
for(;x<=n;x+=lowbit(x))ST::insert(v,w,1,K,root[x]);
}
void work(){
int x,y,k;
for(int i=1;i<=m;i++){
k=que[i].k;x=que[i].x;y=que[i].y;
if(k==0){
update(front[x],val[x],-1);update(next[x]+1,val[x],1);
val[x]=lower_bound(num+1,num+K+1,y)-num;
update(front[x],val[x],1);update(next[x]+1,val[x],-1);
}
else{
int lca=LCA(x,y),s=deep[x]+deep[y]-2*deep[lca]+1;
if(s<k){
printf("invalid request!\n");
continue;
}
k=s-k+1;
bit_one.size=bit_two.size=0;
for(int i=front[x];i;i-=lowbit(i))bit_one.id[++bit_one.size]=root[i];
for(int i=front[y];i;i-=lowbit(i))bit_one.id[++bit_one.size]=root[i];
for(int i=front[lca];i;i-=lowbit(i))bit_two.id[++bit_two.size]=root[i];
for(int i=front[fa[lca]];i;i-=lowbit(i))bit_two.id[++bit_two.size]=root[i];
printf("%d\n",num[ST::query(1,K,k)]);
}
}
}
void init(){
int x,y;
K=n=read();m=read();
for(int i=1;i<=n;i++)num[i]=val[i]=read();
for(int i=1;i<n;i++){
x=read();y=read();
add(x,y);
}
for(int i=1;i<=m;i++){
que[i].k=read();que[i].x=read();que[i].y=read();
if(que[i].k==0)num[++K]=que[i].y;
}
sort(num+1,num+K+1);
K=unique(num+1,num+K+1)-num-1;
for(int i=1;i<=n;i++)val[i]=lower_bound(num+1,num+K+1,val[i])-num;
deep[1]=1;
dfs1(1);
dfs2(1,1);
ST::buildtree();
for(int i=1;i<=n;i++){
update(front[i],val[i],1);
update(next[i]+1,val[i],-1);
}
}
int main(){
init();
work();
return 0;
}