题解[P7357 中位数]
题目链接
我不会告诉你我是因为题目背景的头像与我们班主任一毛一样才来写题解的
题意:
给出一棵树,点有点权,每次将一个点的点权异或
或给出两个点
保证这
\text{Step 1}
先看一下这种定义下的中位数的性质:
对于一个序列
设
则
如果把
由于设成
这套路在 此题 中曾出现过。
\text{Step 2}
对于题目中的满足覆盖
对于一个二分的值
由于要覆盖
设
所以二分时要求的键值的和的最大值就是:
其中
于是希望对每个
\text{Step 3}
考虑如何用主席树维护
对于
当
那这些点的子树内的所有点的
由于主席树是以
这可以用 标记永久化 轻松实现。
\text{Step 4}
现在只剩下最后一个问题:把点权异或
开始建主席树时顺便把每个点的点权异或
由于异或
设
那么
而
所以受改动的版本仅有
若 x 为奇数, t_x=x , 异或后变小成 x-1 。
那原先
所以将
若 x 为偶数, t_x=x+1 ,异或后变大成 x+1
那原先
所以将
这同样可用标记永久化实现。
\text{Step 5}
预处理时间复杂度为
更改点权的时间复杂度单次为
查询要套个二分,单次
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,nn,x,y,opt,tot,tt,l,L,R,mid,cnt,qx,qy;
int a[N],b[N],rt[N],ii[N];
int dfn[N],rev[N],sz[N],dep[N],f[N][20];
int to[N],nextn[N],h[N],edg;char ch;
inline void add(int x,int y){to[++edg]=y,nextn[edg]=h[x],h[x]=edg;}
#define id(x) lower_bound(b+1,b+nn+1,x)-b
struct tree{int l,r,tag,mx;}t[N<<5];
inline void read(int &x){
x=0;ch=getchar();while(ch<48||ch>57)ch=getchar();
while(ch>47&&ch<58)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
void write(int x){if(x>9)write(x/10);putchar(48+x%10);}
void build(int &k,int l,int r){
k=++tot;
if(l^r){
int mid=(l+r)>>1;
build(t[k].l,l,mid);build(t[k].r,mid+1,r);
t[k].mx=max(t[t[k].l].mx,t[t[k].r].mx);
}
else t[k].mx=dep[rev[l]];
}
void update(int &k,int kk,int l,int r,int x,int y,int v){
k=++tot;t[k]=t[kk];
if(x<=l&r<=y)t[k].tag+=v,t[k].mx+=v;
else {
int mid=(l+r)>>1;
if(x<=mid)update(t[k].l,t[kk].l,l,mid,x,y,v);
if(mid<y)update(t[k].r,t[kk].r,mid+1,r,x,y,v);
t[k].mx=max(t[t[k].l].mx,t[t[k].r].mx)+t[k].tag;
}
}
int inquiry(int k,int l,int r,int pos){
if(l^r){
int mid=(l+r)>>1;
if(pos<=mid)return inquiry(t[k].l,l,mid,pos)+t[k].tag;
else return inquiry(t[k].r,mid+1,r,pos)+t[k].tag;
}
else return t[k].mx;
}
int inquiry_mx(int k,int l,int r,int x,int y){
if(x<=l&&r<=y)return t[k].mx;
int mid=(l+r)>>1;
if(x<=mid&&mid<y)
return max(inquiry_mx(t[k].l,l,mid,x,y),inquiry_mx(t[k].r,mid+1,r,x,y))+t[k].tag;
else if(x<=mid)return inquiry_mx(t[k].l,l,mid,x,y)+t[k].tag;
else return inquiry_mx(t[k].r,mid+1,r,x,y)+t[k].tag;
}
void init(int x,int anc){
int i,y;rev[dfn[x]=++tt]=x;
sz[x]=1;dep[x]=dep[anc]+1;f[x][0]=anc;
for(i=1;i^20;++i)f[x][i]=f[f[x][i-1]][i-1];
for(i=h[x];y=to[i],i;i=nextn[i])if(y^anc)init(y,x),sz[x]+=sz[y];
h[x]=0;
}
int lca(int x,int y){
int i;if(dep[x]<dep[y])x^=y^=x^=y;
for(i=19;~i;--i)if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
for(i=19;~i;--i)if(f[x][i]^f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
main(){
read(n);read(m);register int i,j;
for(i=1;i<=n;++i){read(a[i]),b[++nn]=a[i];if(a[i]^1)b[++nn]=a[i]^1;}
sort(b+1,b+nn+1);nn=unique(b+1,b+nn+1)-b-1;
for(i=1;i^n;++i)read(x),read(y),add(x,y),add(y,x);
init(1,0);edg=0;build(rt[0],1,n);
for(i=1;i<=n;++i)add(ii[i]=id(a[i]),i),ii[i]+=(a[i]&1)^1;
for(i=1;rt[i]=rt[i-1],i<=nn;++i)for(j=h[i-1];x=to[j],j;j=nextn[j])
update(rt[i],rt[i],1,n,dfn[x],dfn[x]+sz[x]-1,-2);
while(m--){
read(opt);read(x);
if(opt==1){
i=ii[x];
if(a[x]&1)update(rt[i],rt[i],1,n,dfn[x],dfn[x]+sz[x]-1,-2);
else update(rt[i],rt[i],1,n,dfn[x],dfn[x]+sz[x]-1,2);
a[x]^=1;
}
else {
read(y);l=lca(x,y);
L=0;R=nn;
while(L<R){
mid=L+R+1>>1;cnt=0;
cnt+=inquiry_mx(rt[mid],1,n,dfn[x],dfn[x]+sz[x]-1);
cnt+=inquiry_mx(rt[mid],1,n,dfn[y],dfn[y]+sz[y]-1);
cnt-=(inquiry(rt[mid],1,n,dfn[l])<<1)+(a[l]>=b[mid]?-1:1);
if(cnt>=0)L=mid;else R=mid-1;
}
write(b[L]);putchar('\n');
}
}
}