zoukankan      html  css  js  c++  java
  • dtoi4544「HNOI2016」网络

    题意:

         给定一棵树,每次有 $3$ 种操作

    1. 添加一条从 $u$ 到 $v$ 的重要度为 $d$ 的路径
    2. 删除一条以前添加的路径
    3. 询问当前时刻不经过点 $x$ 的路径中,重要度最大的路径的重要度

    题解:

         考虑对于一个添加或删除操作,可以树链剖分之后在经过的路径上打上重要度的标记,然后查询的时候就可以知道所有经过某个点的路径了。然而这样并没有什么用,显然要求的是这东西的补集。如果先求集合再求补集,是无法完成的,因为集合元素太多。此时考虑在添加操作的时候(删除操作同理),在不经过的点上打上重要度标记,然后查询就可以直接查询最大值。如何在不经过的点上打上标记?可以先树链剖分找出经过的点的区间,只有 $log$ 个,而且这些区间是互不重叠的。然后区间与区间的“间隙”就是不经过的点的区间,同样只有 $log$ 个。之后用线段树+multiset+标记永久化即可维护。

    #include<cstdio>
    #include<vector>
    #include<set>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int n,m,fa[22][100002],tim,ta[200002],tb[200002],td[200002],len;
    multiset<int>q[400002];
    vector<int>g[100002];
    typedef struct{
        int zjds,dfn,dep,zlt,xzd;
    }P;
    typedef struct{
        int l,r;
    }PP;
    bool cmp(PP aa,PP bb){
        return (aa.l<bb.l || aa.l==bb.l && aa.r<bb.r);
    } 
    P p[100002];
    PP t[100002];
    int lca(int x,int y){
        if (p[x].dep<p[y].dep)swap(x,y);
        int k=p[x].dep-p[y].dep;
        for (int i=0;i<=20;i++)
        if ((1<<i)&k)x=fa[i][x];
        if (x==y)return x;
        for (int i=20;i>=0;i--)
        if (fa[i][x]!=fa[i][y])
        {
            x=fa[i][x];y=fa[i][y];
        }
        return fa[0][x];
    }
    void dfs1(int x,int y){
        int Max=0,maxn=-1;
        p[x].zjds=1;p[x].dep=p[y].dep+1;fa[0][x]=y;
        for (int i=0;i<g[x].size();i++)
        if (g[x][i]!=y)
        {
            dfs1(g[x][i],x);p[x].zjds+=p[g[x][i]].zjds;
            if (p[g[x][i]].zjds>Max)
            {
                Max=p[g[x][i]].zjds;maxn=g[x][i];
            }
        }
        p[x].xzd=maxn;
    }
    void dfs2(int x,int y){
        p[x].dfn=++tim;
        if (p[y].xzd==x)p[x].zlt=p[y].zlt;else p[x].zlt=x;
        if (p[x].xzd!=-1)dfs2(p[x].xzd,x);
        for (int i=0;i<g[x].size();i++)
        if (g[x][i]!=p[x].xzd && g[x][i]!=y)dfs2(g[x][i],x);
    }
    void gengxin(int root,int begin,int end,int begin2,int end2,int z){
        if (begin>end2 || end<begin2)return;
        if (begin>=begin2 && end<=end2)
        {
            if (z<0)
            {
                multiset<int>::iterator it=q[root].find(-z);
                q[root].erase(it);
            }
            else q[root].insert(z);
            return;
        }
        int mid=(begin+end)/2;
        gengxin(root*2,begin,mid,begin2,end2,z);gengxin(root*2+1,mid+1,end,begin2,end2,z);
    }
    int chaxun(int root,int begin,int end,int wz){
        if (begin==end)
        {
            if (q[root].empty())return -1;
            multiset<int>::iterator it=q[root].end();it--;
            return (*it);
        }
        int mid=(begin+end)/2;
        if (wz<=mid)
        {
            int ans=-1;
            if (!q[root].empty())
            {
                multiset<int>::iterator it=q[root].end();it--;
                ans=*it;
            }
            return max(ans,chaxun(root*2,begin,mid,wz));
        }
        else
        {
            int ans=-1;
            if (!q[root].empty())
            {
                multiset<int>::iterator it=q[root].end();it--;
                ans=*it;
            }
            return max(ans,chaxun(root*2+1,mid+1,end,wz));
        }
    }
    void work(int u,int v,int d){
        int lc=lca(u,v);len=0;
        while(p[u].dep>=p[lc].dep)
        {
            if (p[p[u].zlt].dep>=p[lc].dep)
            {
                t[++len].l=p[p[u].zlt].dfn;t[len].r=p[u].dfn;
            }
            else
            {
                t[++len].l=p[lc].dfn;t[len].r=p[u].dfn;
            }
            u=fa[0][p[u].zlt];
        }
        while(p[v].dep>=p[lc].dep)
        {
            if (p[p[v].zlt].dep>=p[lc].dep)
            {
                t[++len].l=p[p[v].zlt].dfn;t[len].r=p[v].dfn;
            }
            else
            {
                t[++len].l=p[lc].dfn;t[len].r=p[v].dfn;
            }
            v=fa[0][p[v].zlt];
        }
        sort(t+1,t+len+1,cmp);
        for (int i=2;i<=len;i++)
        if (t[i].l-1>=t[i-1].r+1)gengxin(1,1,n,t[i-1].r+1,t[i].l-1,d);
        if (t[1].l>1)gengxin(1,1,n,1,t[1].l-1,d);
        if (t[len].r<n)gengxin(1,1,n,t[len].r+1,n,d);
    } 
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);g[v].push_back(u);
        }
        dfs1(1,0);dfs2(1,0);
        for (int i=1;i<=20;i++)
        for (int j=1;j<=n;j++)
        fa[i][j]=fa[i-1][fa[i-1][j]];
        for (int i=1;i<=m;i++)
        {
            int op;
            scanf("%d",&op);
            if (op==0)
            {
                scanf("%d%d%d",&ta[i],&tb[i],&td[i]);
                work(ta[i],tb[i],td[i]);
            }
            else if (op==1)
            {
                int sk;scanf("%d",&sk);
                work(ta[sk],tb[sk],-td[sk]);
            }
            else
            {
                int x;scanf("%d",&x);
                printf("%d
    ",chaxun(1,1,n,p[x].dfn));
            }
        }
        return 0;
    }
  • 相关阅读:
    那些离不开的 Chrome 扩展插件
    Spring Boot 实战 —— 入门
    Maven 学习笔记
    Linux lvm 分区知识笔记
    Linux 双向 SSH 免密登录
    CentOS Yum 源搭建
    Ubuntu 系统学习
    iOS 测试三方 KIF 的那些事
    Swift 网络请求数据与解析
    iOS Plist 文件的 增 删 改
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/14397945.html
Copyright © 2011-2022 走看看