一本通1554【例 3】异象石

1554:【例 3】异象石

时间限制: 1000 ms         内存限制: 524288 KB

题目描述

原题来自:Contest Hunter Round #56

在 Adera 的异时空中有一张地图。这张地图上有 N 个点,有 N?1 条双向边把它们连通起来。起初地图上没有任何异象石,在接下来的 M 个时刻中,每个时刻会发生以下三种类型的事件之一:

  1. 地图的某个点上出现了异象石(已经出现的不会再次出现);
  2. 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点);
  3. 向玩家询问使所有异象石所在的点连通的边集的总长度最小是多少。

请你作为玩家回答这些问题。下图是一个例子,灰色节点表示出现了异象石,加粗的边表示被选为连通异象石的边集。

输入格式

第一行有一个整数 N,表示点的个数;

接下来 N?1 行每行三个整数 x,y,z,表示点 x 和 y 之间有一条长度为 z 的双向边;

第 N+1 行有一个正整数 M;

接下来 M 行每行是一个事件,事件是以下三种格式之一:

  • + x:表示点 x 上出现了异象石;
  • - x:表示点 x 上的异象石被摧毁;
  • ?:表示询问使当前所有异象石所在的点连通所需的边集的总长度最小是多少。

输出格式

对于每个 ? 事件,输出一个整数表示答案。

样例

样例输入

6
1 2 1
1 3 5
4 1 7
4 5 3
6 4 2
10
+ 3
+ 1
?
+ 6
?
+ 5
?
- 6
- 3
?

样例输出

5
14
17
10

数据范围与提示

对于 30% 的数据,1≤?n,m?≤?10^3;

对于另 20% 的数据,地图是一条链,或者一朵菊花;

对于 100% 的数据,1≤?n,m?≤?10^5,1?≤?x,y?≤?n,x?!=y,1?≤?z?≤?10^9。

sol:先考虑下给你一堆点怎么求把他们全部连起来需要的费用,发现就是从一个点以任意顺序依次遍历每个点再回到出发点的边权和的1/2,之后就会容易一点,假定这是以dfs遍历的,弄一个set,加点删点是对应的加上几条路径或减去几条就可以了

#include <bits/stdc++.h>
using namespace std;
const int N=100005,M=200005,inf=0x3f3f3f3f;
int n,m;
struct Tree
{
    int tot,Next[M],to[M],val[M],head[N];
    inline void add(int x,int y,int z)
    {
        Next[++tot]=head[x];
        to[tot]=y;
        val[tot]=z;
        head[x]=tot;
        return;
    }
    int Id_cnt,Id[N],Xuhao[N]; //dfs序
    bool Inset[N];
    int Depth[N],F[N][23];
    long long Dis[N];
    inline void dfs(int x,int fa)
    {
        Id[++Id_cnt]=x; Xuhao[x]=Id_cnt;
        F[x][0]=fa; Depth[x]=Depth[fa]+1;
        int i;
        for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
        {
            Dis[to[i]]=Dis[x]+val[i];
            dfs(to[i],x);
        }
        return;
    }
    set<int>Set;
    inline void Pre()
    {
        int i,j;
        dfs(1,0);
        for(i=1;i<=19;i++)
        {
            for(j=1;j<=n;j++) F[j][i]=F[F[j][i-1]][i-1];
        }
        Set.insert(-inf); Set.insert(inf);
        return;
    }
    inline int Ask_Lca(int x,int y)
    {
        int i;
        if(Depth[x]<Depth[y]) swap(x,y);
        for(i=19;~i;i--) if(Depth[F[x][i]]>=Depth[y])
        {
            x=F[x][i];
        }
        if(x==y) return x;
        for(i=19;~i;i--) if(F[x][i]!=F[y][i])
        {
            x=F[x][i]; y=F[y][i];
        }
        return F[x][0];
    }
    inline long long Ask_Dis(int x,int y)
    {
        return Dis[x]+Dis[y]-(Dis[Ask_Lca(x,y)]<<1);
    }
    long long Dis_All;
    inline void Point_Add(int x)
    {
        if(Inset[Xuhao[x]]) return;
        Set.insert(Xuhao[x]); Inset[Xuhao[x]]=1;
        set<int>::iterator it=Set.upper_bound(Xuhao[x]);
        int p2=(*it),p1=(*(--(--it)));
//        printf("%d %d\n",p1,p2);
//        puts("EEE");
        if(p1!=-inf) Dis_All+=Ask_Dis(Id[p1],x);
        if(p2!=inf) Dis_All+=Ask_Dis(x,Id[p2]);
//        puts("FFF");
        if((p1!=-inf)&&(p2!=inf)) Dis_All-=Ask_Dis(Id[p1],Id[p2]);
        return;
    }
    inline void Point_Del(int x)
    {
        if(!Inset[Xuhao[x]]) return;
        Set.erase(Xuhao[x]); Inset[Xuhao[x]]=0;
        set<int>::iterator it=Set.upper_bound(Xuhao[x]);
        int p2=(*it),p1=(*(--it));
        if(p1!=-inf) Dis_All-=Ask_Dis(Id[p1],x);
        if(p2!=inf) Dis_All-=Ask_Dis(x,Id[p2]);
        if((p1!=-inf)&&(p2!=inf)) Dis_All+=Ask_Dis(Id[p1],Id[p2]);
        return;
    }
    inline long long Get_ans()
    {
        long long DD=(Set.size()>3)?(Ask_Dis(Id[*(Set.upper_bound(-inf))],Id[*(--Set.lower_bound(inf))])):0;
        return (Dis_All+DD)>>1;
    }
    inline void Init()
    {
        tot=Dis_All=Id_cnt=0;
        memset(head,0,sizeof head);
        memset(Inset,0,sizeof Inset);
        return;
    }
}T;
int main()
{
//    freopen("stone6.in","r",stdin);
//    freopen("my.out","w",stdout);
    int i;
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        T.add(x,y,z); T.add(y,x,z);
    }
    T.Pre();
    scanf("%d",&m);
    for(i=1;i<=m;i++)
    {
        char Ch[5];
        int x;
        scanf("%s",Ch+1);
        switch (Ch[1])
        {
            case ‘+‘:
                scanf("%d",&x);
                T.Point_Add(x);
                break;
            case ‘-‘:
                scanf("%d",&x);
                T.Point_Del(x);
                break;
            case ‘?‘:
                printf("%lld\n",T.Get_ans());
                break;
            default:
                break;
        }
    }
    return 0;
}
/*
input
6
1 2 1
1 3 5
4 1 7
4 5 3
6 4 2
10
+ 3
+ 1
?
+ 6
?
+ 5
?
- 6
- 3
?
output
5
14
17
10
*/

原文地址:https://www.cnblogs.com/gaojunonly1/p/10352761.html

时间: 2024-08-30 16:01:37

一本通1554【例 3】异象石的相关文章

「一本通 4.4 例 3」异象石 与 [SDOI2015]寻宝游戏

这两个题差不多先说异象石把 主要是找到本题规律,将所加入的点按dfs序排序,记录为a[1],a[2]..a[n]则当前的答案为每个点与前一个点的距离(第一个点则与最后一点) 当然要动态维护答案,每加入一个点就+与前驱的距离+与后驱的距离-前驱与后驱的距离(删点的话ans减去这个值就好 不过异象石最后的答案要/2: 至于维护的话用set就好 1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 cons

Luogu P3320 [SDOI2015]寻宝游戏 / 异象石 【LCA/set】

期末考试结束祭! 在期末考试前最后一发的测试中,异象石作为第二道题目出现QAQ.虽然知道是LCA图论,但还是敲不出来QAQ. 花了两天竞赛课的时间搞懂(逃 异象石(stone.pas/c/cpp)题目描述Adera 是 Microsoft 应用商店中的一款解谜游戏.异象石是进入 Adera 中异时空的引导物,在 Adera 的异时空中有一张地图.这张地图上有 N 个点,有 N-1 条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的 M个时刻中,每个时刻会发生以下三种类型的事件之一:1.

CH#56C 异象石

异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一: 1. 地图的某个点上出现了异象石(已经出现的不会再次出现): 2. 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点): 3. 向玩家询问使所有异象石所在的点连通的边集

【NOIP模拟赛】异象石

Description Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上有N个点,有N-1条双向边把它们连通起来.起初地图上没有任何异象石,在接下来的M个时刻中,每个时刻会发生以下三种类型的事件之一: 1.地图的某个点上出现了异象石(已经出现的不会再次出现): 2.地图某个点上的异象石被摧毁(不会摧毁没有异象石的点): 3.向玩家询问使所有异象石所在的点连通的边集的总长度最小是多少. 请你作为玩家回答这

异象石/[SDOI2015]寻宝游戏

AcWing 异象石 洛咕 寻宝游戏 题意:Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图. 这张地图上有\(N(N<=1e5)\)个点,有\(N-1\)条双向边把它们连通起来. 起初地图上没有任何异象石,在接下来的\(M(M<=1e5)\)个时刻中,每个时刻会发生以下三种类型的事件之一: 地图的某个点上出现了异象石(已经出现的不会再次出现); 地图某个点上的异象石被摧毁(不会摧毁没有异象石的点); 向玩家询问

异象石

题目描述 思路 一本通的描述比较详细 比较好的博客 代码 #include <cstdio> #include <cstring> #include <set> #include <iterator> #define FOR(a, n) for(int i = 1; i <= (n); ++i) using namespace std; const int MAX = 1e5 + 5; int n, m; long long ans; int head

异象石——最近公共祖先

题目链接: https://www.acwing.com/problem/content/357/ 题意: 给出一个树上节点的集合,动态加入或者删除节点,询问连通所有节点的最小边集的权值之和. 解法: 把集合中的节点按照时间戳排序,每相邻两个节点距离以及首尾节点距离累加,累加之和为答案的两倍.(目前不会证明) 节点排序用set维护,首先加入0和inf,以便修改. 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef lo

京东-2017-异或

题目描述 : 现在输入两个n位二进制数,输出它们异或结果的十进制答案.上述样例中异或的二进制结果为1000,转化成十进制就是8. 输入: 输入有三行,第一行一个数n(1<=n<=20),接下来两行有两个n位二进制数.输入的二进制数可能有前导零. 输出 输出一个数,异或结果的十进制数值,不要输出前导零. 样例输入 4 1100 0100 输出:异或的十进制结果. 其实很无脑,把数值转成十进制直接用异或来算就行. #include<bits/stdc++.h> using namesp

CH Round #56 - 国庆节欢乐赛解题报告

最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树,其中一些树上结有能够产生能量的魔力水果.已知每个水果的位置(Xi,Yi)以及它能提供的能量Ci.然而,魔幻森林在某些时候会发生变化:(1) 有两行树交换了位置.(2) 有两列树交换了位置.当然,树上结有的水果也跟随着树一起移动.不过,只有当两行(列)包含的魔力水果数都大于0,或者两行(列)都没有魔