BZOJ 4538 [Hnoi2016]网络

来源:互联网 发布:手机足球关注软件 编辑:程序博客网 时间:2024/04/30 10:43

线段树上二分+链交+LCA

这题做法大概有2种,我用的是第二种

1.实际上一条链的贡献是这条链在树上的补集,于是树剖线段树维护树,每一个节点开一个堆维护最大贡献。 O(nlog3n)

2.假设对于一个询问x,二分出一个答案C,若所有≥C的链都经过了x,则显然最终答案<C,否则最终答案≥C。于是离线将所有链按权排序后,建立权值线段树,节点存储子节点的链交,直接在线段树上二分找答案即可,O(nlog2n),如果把LCA优化成O(1)即可做到O(nlogn)

顺便补充一下如何求链交,网络上求链交的看不懂,于是只好自己脑补一个。

记链为(LCA,a,b),a,b为两端点,链的深度指LCA的深度,定义max(a,b)为取a,b中深度大的,lca(a,b)为取a,b的LCA。

先判断有没有交,方法是判断深度大链的LCA在不在深度小的链上,若不在则无交集。

否则有交,
若LCA1 = LCA2 ,链交的LCA不变,两端点分别取max即可,就不详细说了。
若LCA1 ≠ LCA2,根据脑补+画图可以知道链交的两个端点分别是
a = max( lca(a1,b2), lca(a2,b1) )
b = max( lca(a1,a2), lca(b1,b2) )
这个式子应该具有一般性,可以直接套用(只是常数比较大)

#include<cstdio>#include<algorithm>#define N 200005#define H 20#define reg registerusing namespace std;namespace runzhe2000{    const int INF = 1<<30;    int ecnt, last[N], cnt, timer, beg[N], end[N], fa[N], dep[N], list[N*4], que[N], ST[N*4][H], pos[N], log[N*4], bin[H];    struct edge{int next,to;}e[N<<1];    struct opt    {        int type, a, b, v;    }q[N];    struct chain    {        int lca, a, b;        inline bool in(reg int x)        {            if(lca == 0)return false;            else if(lca == -1)return true;            return beg[lca] <= beg[x] && beg[x] <= end[lca] &&( (beg[x] <= beg[a] && beg[a] <= end[x]) || (beg[x] <= beg[b] && beg[b] <= end[x]) );        }    };    struct seg    {        int l, r, v, tot;        chain c;    }t[N*5];    bool cmp(int a, int b){return q[a].v < q[b].v;}    void addedge(reg int a, reg int b)    {        e[++ecnt] = (edge){last[a], b};        last[a] = ecnt;    }    inline int dep_min(reg int x, reg int y){return dep[x] < dep[y] ? x : y;}    inline int dep_max(reg int x, reg int y){return dep[x] > dep[y] ? x : y;}    void dfs(int x)    {        dep[x] = dep[fa[x]] + 1;        list[++timer] = x;        beg[x] = timer;        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to;            if(y == fa[x])continue;            fa[y] = x;            dfs(y);            list[++timer] = x;        }        end[x] = timer;    }    void build_ST()    {        dep[0] = INF;        bin[0] = 1;for(int i = 1; i < H; i++)bin[i] = bin[i-1] << 1;        for(reg int i = 2; i <= timer; i++)log[i] = 1 + log[i>>1];        for(reg int i = 1; i <= timer; i++)ST[i][0] = list[i];        for(reg int j = 1; j < H; j++)            for(reg int i = 1; i <= timer; i++)                ST[i][j] = dep_min(ST[i][j-1], ST[i+bin[j-1]][j-1]);    }    int ask_lca(reg int x, reg int y)    {        if(x==y)return x;        reg int a = beg[x], b = beg[y];        if(a>b)swap(a,b);        reg int len = b-a+1;        return dep_min(ST[a][log[len]], ST[b-bin[log[len]]+1][log[len]]);    }    void pushup(int x)    {        int lson = x<<1, rson = x<<1|1, u, v;        if(t[lson].c.lca == -1)t[x].c = t[rson].c;        else if(t[rson].c.lca == -1)t[x].c = t[lson].c;        else if(t[lson].c.lca == 0 || t[rson].c.lca == 0)t[x].c = (chain){0,0,0};        else if(!t[lson].c.in(t[rson].c.lca) && !t[rson].c.in(t[lson].c.lca))t[x].c = (chain){0,0,0};        else if(t[lson].c.lca == t[rson].c.lca)        {            u = dep_max(ask_lca(t[lson].c.a, t[rson].c.a), ask_lca(t[lson].c.a, t[rson].c.b));            v = dep_max(ask_lca(t[lson].c.b, t[rson].c.a), ask_lca(t[lson].c.b, t[rson].c.b));            t[x].c = (chain){t[lson].c.lca, u, v};        }        else        {            u = dep_max(ask_lca(t[lson].c.a, t[rson].c.b), ask_lca(t[lson].c.b, t[rson].c.a));            v = dep_max(ask_lca(t[lson].c.a, t[rson].c.a), ask_lca(t[lson].c.b, t[rson].c.b));            t[x].c = (chain){ask_lca(u, v), dep_min(u,v), dep_max(u,v)};        }        if(t[x].c.lca==-1 || t[x].c.lca==0)t[x].v=-1;        else t[x].v=max(t[lson].v, t[rson].v);        t[x].tot = t[x<<1].tot + t[x<<1|1].tot;    }    void build(int x, int l, int r)    {        t[x].l = l;        t[x].r = r;        t[x].c = (chain){t[x].v = -1,0,0};        t[x].tot = 0;        if(l==r)return;        int mid = (l+r)>>1;        build(x<<1,l,mid);        build(x<<1|1,mid+1,r);    }    void modify(reg int x, reg int p, reg int id)    {        if(t[x].l==t[x].r)        {            if(!id)t[x].c = (chain){-1,0,0}, t[x].v=-1, t[x].tot = 0;            else t[x].c = (chain){ask_lca(q[id].a, q[id].b), q[id].a, q[id].b}, t[x].v=q[id].v, t[x].tot = 1;            return;        }        int mid = (t[x].l+t[x].r)>>1;        if(p<=mid)modify(x<<1,p,id);        else modify(x<<1|1,p,id);        pushup(x);    }    int query(reg int x, reg int p)    {        if(t[x].l == t[x].r)return t[x].c.in(p)?-1:t[x].v;        else if(!t[x<<1|1].c.in(p))return query(x<<1|1,p);        else return query(x<<1,p);    }    void main()    {        int n, m;        scanf("%d%d",&n,&m);        for(reg int i = 1, a, b; i < n; i++)        {            scanf("%d%d",&a,&b);            addedge(a,b);            addedge(b,a);        }        dfs(1);        build_ST();        for(reg int i = 1; i <= m; i++)        {            scanf("%d",&q[i].type);            if(q[i].type == 0)            {                que[++cnt] = i;                scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].v);            }            else if(q[i].type == 1)                scanf("%d",&q[i].v);            else                scanf("%d",&q[i].v);        }        sort(que+1,que+cnt+1,cmp);        for(reg int i = 1; i <= cnt; i++)pos[que[i]] = i;        if(cnt)build(1,1,cnt);        for(reg int i = 1; i <= m; i++)        {            if(q[i].type == 0)                modify(1,pos[i],i);            else if(q[i].type == 1)                modify(1,pos[q[i].v],0);            else            {                   if(!t[1].tot || t[1].c.in(q[i].v))printf("-1\n");                else printf("%d\n",query(1,q[i].v));            }        }    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击