[BZOJ4538/Luogu3250][HNOI2016]网络(树链剖分,线段树,堆)

发布于 2018-04-17  69 次阅读


本文章由SYCstudio或本站其它作者所有,严禁转载,转载必究

本文链接地址:[BZOJ4538/Luogu3250][HNOI2016]网络(树链剖分,线段树,堆)

Description

一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:1. 在某两个服务器之间出现一条新的数据交互请求;2. 某个数据交互结束请求;3. 某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。

Tag

树链剖分,线段树,堆

解决思路

把路径拆成覆盖不是这个的其他点,这样转化为补集问题,这样就比较好处理单点询问了。可以树链剖分后用线段树套堆的方法解决。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;

#define ll long long
#define mem(Arr,x) memset(Arr,x,sizeof(Arr))

const int maxN=100100;
const int maxM=maxN*2;
const int inf=2147483647;

class Heap//自己写的可删除堆
{
public:
    priority_queue<int> Q,Del;
    void MainTain(){
        while ((!Q.empty())&&(!Del.empty())&&(Q.top()==Del.top())) Q.pop(),Del.pop();
    }
    bool Empty(){
        MainTain();
        return (Q.size()-Del.size())==0;
    }
    void Push(int x){
        MainTain();
        Q.push(x);return;
    }
    int Top(){
        MainTain();
        return Q.top();
    }
    void Pop(){
        MainTain();Q.pop();
    }
    void Delete(int x){
        MainTain();Del.push(x);MainTain();return;
    }
};

class SegmentData
{
public:
    Heap H;
    int ls,rs;
};

class Range
{
public:
    int l,r;
};

int n,m,root,nodecnt;
int edgecnt=0,Head[maxN],Next[maxM],V[maxM];
SegmentData S[maxN<<2];
int Hson[maxN],Top[maxN],Fa[maxN],Size[maxN],Depth[maxN];
int idcnt,Id[maxN];
int PU[maxN*2],PV[maxN*2],PW[maxN*2];

bool operator < (Range A,Range B);
void Add_Edge(int u,int v);
void dfs1(int u,int fa);
void dfs2(int u,int top);
vector<Range> GetPath(int u,int v);
void Modify(int &now,int l,int r,int ql,int qr,int key,int opt);
int Query(int now,int l,int r,int pos);

int main()
{
    mem(Head,-1);
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        Add_Edge(u,v);Add_Edge(v,u);
    }
    Depth[n]=1;
    dfs1(n,n);dfs2(n,n);
    int pcnt=0;
    while (m--)
    {
        pcnt++;
        int opt;scanf("%d",&opt);
        if (opt==0)
        {
            scanf("%d%d%d",&PU[pcnt],&PV[pcnt],&PW[pcnt]);
            vector<Range> R=GetPath(PU[pcnt],PV[pcnt]);
            for (int i=0;i<R.size();i++) Modify(root,1,n,R[i].l,R[i].r,PW[pcnt],1);
        }
        if (opt==1)
        {
            int t;scanf("%d",&t);
            vector<Range> R=GetPath(PU[t],PV[t]);
            for (int i=0;i<R.size();i++) Modify(root,1,n,R[i].l,R[i].r,PW[t],-1);
        }
        if (opt==2)
        {
            int x;scanf("%d",&x);
            printf("%d\n",Query(root,1,n,Id[x]));
        }
    }
    return 0;
}

bool operator < (Range A,Range B)
{
    if (A.l!=B.l) return A.l<B.l;
    return A.r<B.r;
}

void Add_Edge(int u,int v)
{
    edgecnt++;Next[edgecnt]=Head[u];Head[u]=edgecnt;V[edgecnt]=v;
    return;
}

void dfs1(int u,int fa)
{
    Size[u]=1;
    for (int i=Head[u];i!=-1;i=Next[i])
        if (V[i]!=fa)
        {
            Fa[V[i]]=u;Depth[V[i]]=Depth[u]+1;
            dfs1(V[i],u);
            Size[u]+=Size[V[i]];
            if (Size[V[i]]>=Size[Hson[u]]) Hson[u]=V[i];
        }
    return;
}

void dfs2(int u,int top)
{
    Top[u]=top;
    Id[u]=++idcnt;
    if (Hson[u]==0) return;
    dfs2(Hson[u],top);
    for (int i=Head[u];i!=-1;i=Next[i])
        if ((V[i]!=Fa[u])&&(V[i]!=Hson[u]))
            dfs2(V[i],V[i]);
    return;
}

vector<Range> GetPath(int u,int v)
{
    //得到树链剖分后的序列
    vector<Range> Ran;Ran.clear();
    while (Top[u]!=Top[v])
    {
        if (Depth[Top[u]]<Depth[Top[v]]) swap(u,v);
        Ran.push_back((Range){Id[Top[u]],Id[u]});
        u=Fa[Top[u]];
    }
    if (Depth[u]>Depth[v]) swap(u,v);
    //把序列转化为补集形式
    Ran.push_back((Range){Id[u],Id[v]});
    sort(Ran.begin(),Ran.end());
    vector<Range> Ret;Ret.clear();
    if (Ran[0].l!=1) Ret.push_back((Range){1,Ran[0].l-1});
    for (int i=1;i<Ran.size();i++) if (Ran[i-1].r+1<=Ran[i].l-1) Ret.push_back((Range){Ran[i-1].r+1,Ran[i].l-1});
    if (Ran[Ran.size()-1].r!=n) Ret.push_back((Range){Ran[Ran.size()-1].r+1,n});
    return Ret;
}

void Modify(int &now,int l,int r,int ql,int qr,int key,int opt)
{
    if (now==0) now=++nodecnt;
    if ((l==ql)&&(r==qr))
    {
        if (opt==1) S[now].H.Push(key);
        else S[now].H.Delete(key);
        return;
    }
    int mid=(l+r)>>1;
    if (qr<=mid) Modify(S[now].ls,l,mid,ql,qr,key,opt);
    else if (ql>=mid+1) Modify(S[now].rs,mid+1,r,ql,qr,key,opt);
    else
    {
        Modify(S[now].ls,l,mid,ql,mid,key,opt);
        Modify(S[now].rs,mid+1,r,mid+1,qr,key,opt);
    }
    return;
}

int Query(int now,int l,int r,int pos)
{
    if (now==0) return -1;
    int Ret=-1;
    if (S[now].H.Empty()==0) Ret=S[now].H.Top();
    if (l==r) return Ret;
    int mid=(l+r)>>1;
    if (pos<=mid) return max(Ret,Query(S[now].ls,l,mid,pos));
    else return max(Ret,Query(S[now].rs,mid+1,r,pos));
}

本文章由SYCstudio或本站其它作者所有,严禁转载,转载必究

本文链接地址:[BZOJ4538/Luogu3250][HNOI2016]网络(树链剖分,线段树,堆)


HNCJ OIer 一枚