蓝桥杯2014年第五届 套娃 线段树 dfs序

题目链接:https://www.dotcpp.com/oj/problem1822.html

题目描述

 作为 drd 送的生日礼物,atm 最近得到了一个俄罗斯娃娃。他对这个俄罗斯娃娃的构造很感兴趣。

    俄罗斯娃娃是一层一层套起来的。假设:一个大小为 x 的俄罗斯娃娃里面可能会放任意多个大小小于 x 的俄罗斯娃娃(而市场上的套娃一般大娃里只能放一个小娃)。

    drd 告诉 atm ,这个俄罗斯娃娃是由 n 个小娃娃组成的,它们的大小各不相同。    我们把这些小娃娃的大小从小到大依次记为 1 到 n 。

    如果 atm 想观赏大小为 k 的小娃娃,他会先看这个小娃娃是否已经在桌子上了。    如果已经在桌子上,那么他就可以观赏了。否则他就打开桌子上某一个俄罗斯娃娃,将它套住的所有的小娃娃拿出来,摆在桌子上。
    一开始桌子上只有 drd 送的大小为 n 的娃娃。注意,他只会将其中所有小娃娃拿出来,如果小娃娃里面还套着另外的小娃娃,他是不会将这些更里层的这些小娃娃拿出来的。
    而且 atm 天生具有最优化的强迫症。他会最小化他所需要打开的娃娃的数目。

    atm 是一个怪人。有时候他只想知道观看大小为 x 的娃娃时需要打开多少个娃娃(但并不去打开);有时候听 drd 说某个娃娃特别漂亮,于是他会打开看。现在请你输出他每次需要打开多少个娃娃。

【输入格式】
第一行两个数 n m ,表示娃娃的数目以及 atm 想看的娃娃的数目。
接下来 n - 1 行,每行两个数 u v,表示大小为 u 的娃娃里面套着一个大小为 v 的娃娃。保证 u > v 。
接下来 m 行,每行形如:
  P x :表示 atm 一定要看到大小为 x 的娃娃;
  Q x :表示 atm 只想知道为了看大小为 x 的娃娃,他需要打开多少个娃娃,但实际上并不打开他们。

【输出格式】
输出 m 行。对应输入中P操作或Q操作需要打开(或假想打开)多少个俄罗斯娃娃。

【样例输入】
5 5
5 3
5 4
3 2
3 1
Q 1
Q 4
P 2
Q 1
Q 4

【样例输出】
2
1
2
0
0

【数据范围】
对于 30% 的数据:n, m <= 1000
对于 100% 的数据:n, m <= 100000

题解:首先说一下,这个代码不对,但我绝对思路没啥问题,感觉是数据问题,emmm,思路就是,先跑一遍dfs序,如果是拆的话,就直接先递归到分支的根节点,然后在扫下来,对应的每一个分支相应的减一,因为他们的父辈减少了,首先这样是不会超时的,因为每个点只会处理一次,然后就是线段树区间更新单点查询,看了数据了,很大,没法自己算,和某些结果要么一样,要么差一,感觉还是数据有点问题

别粘代码,别粘代码!!!!某些oj过不了

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
    int to,nex;
}e[N*2];
struct node1{
    int l,r;
    int laz;
}tree[N<<2];
int head[N],len;
int n,m;
int f[N],ans[N];
int in[N],out[N],cnt;
int p[N];
void add(int x,int y)
{
    e[len].to=y;
    e[len].nex=head[x];
    head[x]=len++;
}
void dfs(int u)
{
    in[u]=++cnt;
    p[cnt]=u;
    int to;
    for(int i=head[u];i!=-1;i=e[i].nex)
    {
        to=e[i].to;
        ans[to]=ans[u]+1;
        dfs(to);
    }
    out[u]=cnt;
}
void build(int l,int r,int cur)
{
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz=0;
    if(l==r)
    {
        tree[cur].laz=ans[p[l]];
        return;
    }
    int mid=(r+l)>>1;
    build(l,mid,cur<<1);
    build(mid+1,r,cur<<1|1);
}
void pushdown(int cur)
{
    if(tree[cur].laz<0)
    {
        tree[cur<<1].laz+=tree[cur].laz;
        tree[cur<<1|1].laz+=tree[cur].laz;
        tree[cur].laz=0;
    }
}
void update(int pl,int pr,int cur,int val)
{
    if(pl<=tree[cur].l && tree[cur].r<=pr)
    {
        tree[cur].laz+=val;
        return;
    }
    pushdown(cur);
    if(pl<=tree[cur<<1].r) update(pl,pr,cur<<1,val);
    if(pr>=tree[cur<<1|1].l) update(pl,pr,cur<<1|1,val);
}
int query(int pos,int cur)
{
    if(tree[cur].l==tree[cur].r)
    {
        return tree[cur].laz;
    }
    pushdown(cur);
    if(pos<=tree[cur<<1].r) return query(pos,cur<<1);
    else return query(pos,cur<<1|1);
}
int tt[N];
int main()
{
    int x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)head[i]=-1;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        f[y]=x;
    }
    for(int i=1;i<=n;i++)
    {
        if(f[i]==0)
        {
            ans[i]=0;
            dfs(i);
            break;
        }
    }
    build(1,n,1);
    char op[2];
    int tmp;
    int l;
    while(m--)
    {
        scanf("%s%d",op,&x);
        if(op[0]=='Q')
        {
            printf("%d\n",query(in[x],1));
        }
        else
        {
            printf("%d\n",query(in[x],1));
            l=0;
            while(f[x]!=0)
            {
                tt[++l]=f[x];
                x=f[x];
            }
            while(l)
            {
                out[tt[l]]=in[tt[l]];
                for(int i=head[tt[l]];i!=-1;i=e[i].nex)
                {
                    y=e[i].to;
                    f[y]=0;
                 //   cout<<y<<" "<<in[y]<<" *** "<<out[y]<<endl;
                    update(in[y],out[y],1,-1);
                       
                }
                l--;
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值