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\n",chaxun(1,1,n,p[x].dfn));
        }
    }
    return 0;
}
posted @ 2021-02-11 17:27  1124828077ccj  阅读(54)  评论(0编辑  收藏  举报