SDUTOJ1755 装备合成(dfs序+线段树)

题目描述

小白很喜欢玩儿LOL,但是无奈自己是个坑货,特别是在装备的选择和合成上,总是站在泉水里为选装备而浪费时间。现在小白试图解决这个问题,为了使问题简单化,我们把游戏中的装备合成规则简化如下:

(1)装备的合成关系构成一棵合成关系树,如图(a)所示,装备的下级装备叫合成小件,直接连接的叫直接合成小件;上级装备叫合成件,直接连接的叫直接合成件。合成树上的每件装备都可以直接购买,如果钱不够也可以先购买这个装备的合成小件。

(2)每个装备都有一个合成价格和一个总价格,装备的总价格=该装备的合成价格+该装备所有直接合成小件的总价格之和(图(a)关系树上面显示的数字就是对应装备的总价格)。

(3)初始的时候(未拥有装备的任何部分),装备的当前价格等于总价格,当前价格会随着购买的小件而发生相应的变化。

(4)如果购买了某个装备,那么它所有上级可合成装备的当前价格都会相应地减少,减少的量等于这个装备的当前价格。

(5)如果购买了某个装备,那么它下级所有合成小件都会被购买,也就是说,这些小件都变成已拥有的状态,但是物品栏里只有最终合成的装备,因为是小件合成了这件装备。

(6)我们认为关系树上的每个装备的直接合成小件都不超过2件,关系树上同一件物品只会出现一次,我们也不考虑物品的出售问题,我们假设物品栏容量无限,金钱无限。

现在问题来了,按照格式给定一棵合成关系树,再给定一系列操作,完成相应的查询,具体格式见输入。

输入

多组输入,对于每组数据:

第一行有两个整数n m,分别代表关系树中物品的数量和后续的操作数。(1 <= n,m <= 10^4)

接下来的n行,每行对应一件物品的描述,格式为equipment p k,分别代表装备的名称,合成价格,直接合成小件的个数,然后有k个合成小件的名称synthesis1 synthesis2 ... synthesisk。(1 <= p <=10^4 , k <= 2 , 所有物品名称只包含小写英文字母,长度不超过20)

接下来的m行,每行对应一个操作,格式如下:

(1)B equipment ,表示物品equipment被购买。

(2)Q equipment ,表示要查询物品equipment的当前价格。

其中equipment代表物品的名称,保证合法且存在于合成关系树中。

注意:如果B指令购买的装备是当前已经拥有的装备(包括小件),那么忽略该条B购买指令。特别地,如果你已经拥有某件装备,那么查询该物品的当前价格时应该输出这件物品的总价格而不是0

输出

对于每次Q查询指令,输出一个整数,代表查询的物品的当前价格。

示例输入

8 10
bannerofcommand 600 2 aegisofthelegion fiendishcodex
aegisofthelegion 400 2 nullmagicmantle crystallinebracer
fiendishcodex 465 1 amplifyingtome
nullmagicmantle 450 0
crystallinebracer 100 2 rubycrystal rejuvenationbead
amplifyingtome 435 0
rubycrystal 400 0
rejuvenationbead 150 0
B crystallinebracer
Q fiendishcodex
Q bannerofcommand
B nullmagicmantle
Q aegisofthelegion
B aegisofthelegion
Q bannerofcommand
Q crystallinebracer
B bannerofcommand
Q bannerofcommand

示例输出

900
2350
400
1500
650
3000

思路:这题很难写,用了dfs序搞出每件装备的范围建线段树,然后线段树实现区间赋0,记录区间和购买一件装备时把他管辖的区间全都标记为拥有,然后区间赋0,向上更新(不用向下管了,不会查询到的)预处理每件装备的总钱数然后查询时如果装备已经拥有,就输出预处理得到的总钱数,如果没有则区间查询它所管辖的区间970ms险过。。
/* ***********************************************
Author        :devil
Created Time  :2016/5/31 10:58:16
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
const int N=10010;
int n,m,r,ys[N],tree[N<<2];
map<string,int>mp;
string s;
bool ru[N];
struct wq
{
    bool f;
    int v;
    int sum;
    int l,r;
}u[N];
vector<int>eg[N];
void dfs(int x)
{
    u[x].l=++r;
    int ans=u[x].v;
    ys[r]=x;
    for(int i=0;i<eg[x].size();i++)
    {
        dfs(eg[x][i]);
        ans+=u[eg[x][i]].sum;
    }
    u[x].r=r;
    u[x].sum=ans;
}
void build(int node,int l,int r)
{
    if(l==r)
    {
        tree[node]=u[ys[l]].v;
        return ;
    }
    int m=(l+r)>>1;
    build(node<<1,l,m);
    build(node<<1|1,m+1,r);
    tree[node]=tree[node<<1]+tree[node<<1|1];
}
void update(int node,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)
    {
        tree[node]=0;
        return ;
    }
    int m=(l+r)>>1;
    if(m>=L) update(node<<1,l,m,L,R);
    if(m<R) update(node<<1|1,m+1,r,L,R);
    tree[node]=tree[node<<1]+tree[node<<1|1];
}
int query(int node,int l,int r,int L,int R)
{
    if(l>=L&&r<=R) return tree[node];
    int m=(l+r)>>1,ans=0;
    if(m>=L) ans+=query(node<<1,l,m,L,R);
    if(m<R) ans+=query(node<<1|1,m+1,r,L,R);
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        mp.clear();
        r=0;
        memset(ru,0,sizeof(ru));
        for(int i=1;i<=n;i++)
            eg[i].clear();
        int cnt=0,k;
        for(int i=0;i<n;i++)
        {
            cin>>s;
            if(mp.find(s)==mp.end()) mp[s]=++cnt;
            int p=mp[s];
            u[p].f=0;
            scanf("%d",&u[p].v);
            scanf("%d",&k);
            while(k--)
            {
                cin>>s;
                if(mp.find(s)==mp.end()) mp[s]=++cnt;
                eg[p].push_back(mp[s]);
                ru[mp[s]]=1;
            }
        }
        for(int i=1;i<=n;i++)
            if(!ru[i])
                dfs(i);
        build(1,1,n);
        char str[2];
        while(m--)
        {
            scanf("%s",str);
            cin>>s;
            int p=mp[s];
            if(str[0]==‘B‘)
            {
                if(u[u[p].l].f) continue;
                for(int i=u[p].l;i<=u[p].r;i++)
                    u[i].f=1;
                update(1,1,n,u[p].l,u[p].r);
            }
            else
            {
                if(u[u[p].l].f) printf("%d\n",u[p].sum);
                else printf("%d\n",query(1,1,n,u[p].l,u[p].r));
            }
        }
    }
    return 0;
}
时间: 2024-07-31 13:07:44

SDUTOJ1755 装备合成(dfs序+线段树)的相关文章

POJ 3321 DFS序+线段树

单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include <cstdio> 6: #include <cstring> 7: #include <cctype> 8: #include <algorithm> 9: #include <vector> 10: #include <iostream> 1

codevs1228 (dfs序+线段树)

总结: 第一次遇到dfs序的问题,对于一颗树,记录节点 i 开始搜索的序号 Left[i] 和结束搜索的序号 Righti[i],那么序号在 Left[i] ~ Right[i] 之间的都是节点 i 子树上的节点. 并且此序号与线段树中 L~R 区间对应,在纸上模拟了几遍确实如此,但暂时还未理解为何对应. 此题就是dfs序+线段树的裸题 代码: #include<iostream> #include<vector> #include<cstring> #include&

[BZOJ 3306]树(dfs序+线段树+倍增)

Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Solution 单点修改子树查询的话可以想到用dfs序+线段树来处理,换根的处理画一画图应该可以明白: 如果查询的x是当前的根rt,直接返回整棵树的min 如果rt在x的子树中,用倍增的方法找到离x最近的rt的祖先t,整棵树除t的子树以外的部分就是x当前根下的子树 如果rt不在x的子树中,查询x原来的子树的min值 #include<iostream> #include<

Educational Codeforces Round 6 E dfs序+线段树

题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili上电子科技大学发的视频学习的 将一颗树通过dfs编号的方式 使每个点的子树的编号连在一起作为相连的区间 就可以配合线段树搞子树 因为以前好像听说过 线段树可以解决一种区间修改和查询区间中不同的xx个数...所以一下子就想到了... 但是我不会写线段树..只会最简单的单点修改区间查询...不会用延迟标

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\),问你答案是多少. \(n\leq {10}^5,k\leq {10}^9\) 题解 设\(l\)为这棵树的叶子个数,显然当\(k>\)树的深度时答案都是\(l\). 下面要证明:答案是\(O(l+\frac{n-l}{k})\)的. 我们从下往上贪心,每次选择一个未被覆盖的深度最深的点,覆盖这个点网

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

Manthan, Codefest 16(G. Yash And Trees(dfs序+线段树))

题目链接:点击打开链接 题意:给你一棵树, 根结点为1, q组操作, 每组操作有两种, 一种是对一个结点的所有子树结点的值全部+1, 另一种是查询一个结点的子树结点上值%m的余数为素数的个数. 思路:对于第一个操作, 我们可以想到用dfs序给树重新标号, 使得一个结点的子树结点为相邻的一条线段, 这样,就可以很容易的用线段树进行处理了.  对于第二个操作, 为了维护一个区间内的值, 我们可以用bitset作为结点信息.  我们可以开一个m位的bitset, 对于每个位, 1表示这个数在此区间中,

cdoj 574 High-level ancients dfs序+线段树

High-level ancients Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/574 Description Love8909 is keen on the history of Kingdom ACM. He admires the heroic undertakings of Lxhgww and Haibo. Inspired by those sagas, L