您的位置:首页 > 理论基础 > 计算机网络

bzoj4538: [Hnoi2016]网络

2017-04-21 14:36 253 查看
传送门

本来想用树剖艹,然而并不会卡常数这种神奇的技能,,,于是还是乖乖写正解吧QAQ

我们可以把一个询问转化为二分判定性问题

二分答案K

,若所有权值大于K的路径都经过询问点x,则答案比K小,否则答案比K大

对于多组询问,外层再套一个整体二分就行了

至于判断有几条路径经过点x

,对于一条路径(u,v)我们把u和v置为1,lca(u,v)和lca(u,v)的父亲置为−1,这样经过一个节点x

的路径条数就是以其为根的子树的标记和,,,

由于子树区间求和有关,于是可以用dfs序维护

然后可以O(1)

求lca,即通过欧拉回路把lca转化为rmq问题。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define N 100005
using namespace std;
pair<int,int> pos
;
struct data{int op,id,x,ans;}q[N*2],tmp[N*2];
struct edge{int to,next;}e[N*2];
int head
,st[N*4][20],log_2[N*2],vis
;
int dep
,A[N*2],B[N*2],C[N*2],bit
,fa
;
int tot,ss,n,m,x,y,tim,mx;
bool cmp(data x,data y){
return x.id<y.id;
}
void add(int x,int y){
e[++tot]=(edge){y,head[x]};
head[x]=tot;
e[++tot]=(edge){x,head[y]};
head[y]=tot;
}
void dfs(int x){
pos[x].fi=++tim;
st[++ss][0]=x;
vis[x]=ss;
for (int i=head[x];i;i=e[i].next)
if (!vis[e[i].to]){
fa[e[i].to]=x;
dep[e[i].to]=dep[x]+1;
dfs(e[i].to);
st[++ss][0]=x;
}
pos[x].se=tim;
}
int Min(int x,int y){
return dep[x]<dep[y]?x:y;
}
void build(){
for (int i=2;i<=ss;i++)
log_2[i]=log_2[i>>1]+1;
for (int j=1;j<=log_2[ss];j++)
for (int i=1;i<=ss;i++)
st[i][j]=Min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int lca(int x,int y){
x=vis[x]; y=vis[y];
if (x>y) swap(x,y);
int len=log_2[y-x+1];
return Min(st[x][len],st[y-(1<<len)+1][len]);
}
void change(int x,int v){
for (;x<=n;x+=x&(-x)) bit[x]+=v;
}
int ask(int x){
int s=0;
for (;x;x-=x&(-x)) s+=bit[x];
return s;
}
void update(int x,int y,int op){
int _lca=lca(x,y);
change(pos[x].fi,op);
change(pos[y].fi,op);
change(pos[_lca].fi,-op);
if (fa[_lca]) change(pos[fa[_lca]].fi,-op);
}
int query(int x){
return ask(pos[x].se)-ask(pos[x].fi-1);
}
void erfen(int L,int R,int l,int r){
if (L>R) return;
int mid=(l+r)>>1;
if (l==r){
for (int i=L;i<=R;i++)
if (q[i].op==2) q[i].ans=mid;
return;
}
int qq=L-1,tt=0,num=0;
for (int i=L;i<=R;i++)
if (q[i].op==2){
if (query(q[i].x)==num)
q[++qq]=q[i];
else tmp[++tt]=q[i];
}
else{
int op=q[i].op?-1:1;
if (C[q[i].x]<=mid) q[++qq]=q[i];
else{
tmp[++tt]=q[i]; num+=op;
update(A[q[i].x],B[q[i].x],op);
}
}
for (int i=1;i<=tt;i++)
if (tmp[i].op!=2){
int op=tmp[i].op?1:-1;
update(A[tmp[i].x],B[tmp[i].x],op);
}
for (int i=1;i<=tt;i++)
q[qq+i]=tmp[i];
erfen(L,qq,l,mid);
erfen(qq+1,qq+tt,mid+1,r);
}
int main(){
//freopen("1.in","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i){
scanf("%d%d",&x,&y);
add(x,y);
}
dfs(1);
build();
for (int i=1;i<=m;i++){
scanf("%d",&q[i].op);
q[i].id=i;
if (q[i].op==0){
scanf("%d%d%d",&A[i],&B[i],&C[i]);
q[i].x=i; mx=max(mx,C[i]);
}
else scanf("%d",&q[i].x);
}
erfen(1,m,-1,mx);
sort(q+1,q+m+1,cmp);
for (int i=1;i<=m;i++)
if (q[i].op==2) printf("%d\n",q[i].ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: