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;
    }
  • 相关阅读:
    [NOI2014]动物园
    2018.7.15模拟赛
    2018.7.13模拟赛
    [CodeForces]920F SUM and REPLACE
    [BZOJ3211]花神游历各国
    [GSS5] Can you answer these queries V
    [SPOJ1716] GSS3
    [HNOI2012]排队
    2018.7.10模拟赛
    7.3模拟赛
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/14397945.html
Copyright © 2011-2022 走看看