BZOJ 3991(dfs序 + LCA 公式推导)

来源:互联网 发布:狮子机平均分打法数据 编辑:程序博客网 时间:2024/06/07 00:20
题意:

给定一颗带权的树(n<=1e5),维护一个动态的集合(即插入点和删除点),求从其中一点出发到达所有点并返回的最小距离。

分析:

到达所有点并返回,是这些点用最少的边连起来的权值的2倍。这样只需动态计算,最少边的和。

这里以1为根节点,跑一遍dfs序。

考虑插入:那么如果插入点得dfs序,在集合中存在点dfs序的中间,找到比之小的最大点,和比之大的最小点,因为插入点在内部这两点连线与该点得距离最小。

否则,插入点在外部,找dfs序最大和最小点,即可。

删除是插入的逆操作。

//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <set>#include <map>#include <string>#include <list>#include <cstdlib>#include <queue>#include <stack>#include <cmath>#include <bitset>#include <cassert>#define ALL(a) a.begin(), a.end()#define clr(a, x) memset(a, x, sizeof a)#define X first#define Y second#define pb push_back#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define rep1(i,x,y) for(int i=x;i<=y;i++)#define rep(i,n) for(int i=0;i<(int)n;i++)using namespace std;const double eps = 1e-10;typedef long long LL;typedef long long ll;typedef pair<int, int> pii;const int oo =0x3f3f3f3f;const int maxn=100000+100;const int DEG=30;struct Edge{    int v, nxt , cap;} edge[maxn<<1];int n, head[maxn], tot, fa[maxn][DEG], deg[maxn], sz[maxn];void init(){    clr(head, -1);    tot=0;}void AddEdge(int u, int v ,int c){    edge[tot].v=v;    edge[tot].cap=c;    edge[tot].nxt=head[u];    head[u]=tot++;}void dfs(int u){    for(int i=1; i<DEG; i++)        fa[u][i]=fa[fa[u][i-1]][i-1];    sz[u]=1;    for(int i=head[u]; ~i; i=edge[i].nxt)    {        int v=edge[i].v;        if(v==fa[u][0])continue ;        deg[v]=deg[u]+1;        fa[v][0]=u;        dfs(v);        sz[u]+=sz[v];    }}int par(int u, int det){    for(int i=0; det; det>>=1, i++)        if(det&1)            u=fa[u][i];    return u;}int LCA(int u, int v){    if(deg[u]>deg[v])swap(u, v);    int tu=u, tv=v;    tv=par(v, deg[v]-deg[u]);    if(tu==tv)return tu;    for(int i=DEG-1; i>=0; i--)    {        if(fa[tu][i]==fa[tv][i])continue ;        tu=fa[tu][i], tv=fa[tv][i];    }    return fa[tu][0];}int id[maxn] , cnt_=0 ;ll d[maxn];void init_dfs(int u,int f , ll len){    id[u] = ++cnt_;    d[u] = len;    for(int i=head[u]; ~i; i=edge[i].nxt)    {        int v=edge[i].v;        if(v==f)continue ;        init_dfs(v,u,len+edge[i].cap);    }}struct node{    int id,u;    node(int u=0,int id=0):u(u),id(id) {}    bool operator<(const node& rhs)const    {        return id < rhs.id;    }};set<node> que;typedef set<node>::iterator set_p;ll now = 0;void cal(int u){    if(que.empty()) {          que.insert(node(u,id[u])); return ;    }    set_p p = que.find(node(u,id[u])) , p1, p2;    int flag = -1;    if(p == que.end())    {        que.insert(node(u,id[u]));        flag = 1;    }     p = que.find(node(u,id[u]));     p1 = p2 = p;  set_p ed = que.end(); --ed;     if(p == que.begin()) p1++,p2=ed;     else if(p == ed) p1=que.begin(),p2=ed,--p2;     else p1--, p2++;     int y = p2->u;     int x = p1->u;     now+=((ll)d[u]-d[LCA(x,u)]-d[LCA(y,u)]+d[LCA(x,y)])*flag;    if(flag == -1) que.erase(p);}int Q;int main(){    scanf("%d %d", &n ,&Q);    init();    for(int i=0; i<n-1; i++)    {        int u, v , c;        scanf("%d%d%d", &u, &v,&c);        AddEdge(u, v , c);        AddEdge(v, u , c);    }    deg[1]=0;    fa[1][0]=1;    dfs(1);    cnt_ = 0; d[1] = 0;    init_dfs(1,-1,0);    que.clear();    now = 0;    while(Q--)    {        int u;        scanf("%d",&u);        cal(u);        printf("%lld\n",now*2);    }}


0 0
原创粉丝点击