bzoj4538: [Hnoi2016]网络

来源:互联网 发布:哈登职业生涯数据预测 编辑:程序博客网 时间:2024/06/14 16:09

传送门
本来想用树剖艹,然而并不会卡常数这种神奇的技能,,,于是还是乖乖写正解吧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 100005using namespace std;pair<int,int> pos[N];struct data{int op,id,x,ans;}q[N*2],tmp[N*2];struct edge{int to,next;}e[N*2];int head[N],st[N*4][20],log_2[N*2],vis[N];int dep[N],A[N*2],B[N*2],C[N*2],bit[N],fa[N];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);}
0 0
原创粉丝点击