HPU 1458 (数状数组,利用的很神奇)

文件统计 [数据结构]

题目描述

“星农”是一个追求效率的公司,公司内的文件管理系统也不例外。现有n个文件夹分别命名为1,2,3…n,它们构成一个文件目录,1作为此文件目录的根目录,其它文件夹均为1号目录的直接子目录或间接子目录。每个目录里初始时没有任何文件。

现在有三种操作:

1.add x y –> 向x号目录里添加y个文件

2.delete x y –> 向x号目录里删除y个文件,如果目录中文件数不足y,则输出”error”,不删除文件并结束本次操作。

3.query x –> 查询从x号文件夹到根目录(1号文件夹),其文件个数之和。

输入

第一行输入一个整数T,表示有T组数据。

T组数据中,第一行输入两个整数n、m,表示有n个目录和m次操作。

接下来n-1行,每行输入两个整数x、y,表示x和y互为父子目录。

然后m行表示m次操作,输入方式见样例及题目描述。

1 ≤ T ≤ 20

1 ≤ n,m,x,y ≤ 23333

输出

对于delete操作,若x号目录文件个数不足y个,则输出”error”(不加双引号);

对于query操作,输出一个整数表示要查询信息。

样例输入

1
5 5
1 2
2 4
2 5
1 3
add 5 2
query 2
delete 3 1
add 1 5
query 5

样例输出

0
error
7

地址:http://acm.hpu.edu.cn/problem.php?id=1458

这道题刚开始我一看就知道是线段树和树状数组能解决的,但是自己一直想不懂怎么用
MY 一直想分层 每次只要算上一层的加上自己这层的,一直超时,看了题解后发现了一个大坑 接下来n-1行,每行输入两个整数x、y,表示x和y互为父子目录。就是标红的这一句,他只说明了是父子关系而并没有说明谁是父谁是子,后来研究了一会发现我的思路也有问题,当分支多时会出bug 如果一个文件夹的父文件夹那一级有多个,就会出错!!!

正确思路 :题解思路!!
先看图
图片有点大
就例如这个 先用dfs跑一边 以那个顺序作为树状数组 dj1(图上为up) 代表进入文件夹的时间 dj2(图上为down)是出文件夹的时间.看添加,例如在二号文件夹添加文件 那么受到影响的就是 2 4 5 6 2 那么如何让后面的不搜影响呢 所以就要在 dj1的位置加上文件数 而在dj2处减去文件数,这样受到影响的就只有他们中间的了,另外开个数组存下每个文件夹里的文件数,方便del

由于改了多次有点乱,先凑活吧

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rd(a) scanf("%d",&a)
#define rl(a) scanf("%lld",&a)
#define inf 0x3f3f3f3f
ll sum[56667];
int  dj1[23337];
int dj2[23337];
ll  vis[23337];
int o;
struct node
{

    int v,next;

} ss[46679];
int head[23338];
inline void tre_add(int u,int v)
{

    ss[o].next=head[u];
    ss[o].v=v;
    head[u]=o++;


}
void add(int x,int val,int n)
{

    while(x<=n)
    {

        sum[x]+=val;
        x+=x&-x;

    }


}
ll query(int x)
{

    ll ans=0;
    while(x>0)
    {

        ans+=sum[x];
        x-=x&-x;
    }
    return ans;


}
int v[23399];
int cnt;
void dfs(int ii)
{

    dj1[ii]=cnt++;
    for(int i=head[ii]; ~i; i=ss[i].next)
    {

        if(!v[ss[i].v])
        {
        v[ss[i].v]=1;
        dfs(ss[i].v);
        }

    }
    dj2[ii]=cnt++;

}

int main()
{
    //freopen("in.txt", "r", stdin);
    int t;
    rd(t);

    while(t--)
    {
        o=0;cnt=1;
        memset(v,0,sizeof(v));
        memset(vis,0,sizeof(vis));
        memset(sum,0,sizeof(sum));
        memset(head,-1,sizeof(head));
        int n,m;
        rd(n),rd(m);
        for(int i=1; i<n; i++)
        {
            int a,b;
            rd(a);
            rd(b);
            tre_add(a,b);
            tre_add(b,a);

        }
        v[1]=1;
        dfs(1);
        for(int i=0; i<m; i++)
        {

            char s[30];
            int a,b;
            scanf("%s",s);
            if(s[0]=='a')
            {
                rd(a);
                rd(b);
                add(dj1[a],b,2*n);
                add(dj2[a],-b,2*n);
                vis[a]+=b;

            }
            else if(s[0]=='q')
            {

                rd(a);
                ll k=query(dj1[a]);
                printf("%lld\n",k);

            }
            else
            {

                rd(a);
                rd(b);
                if(vis[a]<b)
                {


                    puts("error");


                }
                else
                {

                    vis[a]-=b;
                    add(dj1[a],-b,2*n);
                    add(dj2[a],b,2*n);
                }

            }


        }



    }






    return 0;
}

官方题解 :http://acm.hpu.edu.cn/showsource.php?id=74552

加油!!

猜你喜欢

转载自blog.csdn.net/qq_37493070/article/details/78787340