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, Love8909 picked up his courage and tried to build up his own kingdom. He named it as A230.

After hard working for several years, Love8909 is about to fulfill his dream. However, there is still one thing to do: setting up the defense network. As Kingdom EDC looks at territory and people of A230 fiercely as a tiger does, Love8909 has to make it as soon as possible.

The defense network Love8909 wants to use is the same as the one used by Lxhgww and Haibo. He also connects all cities with roads which form a tree structure, and the capital city is City 1, which is the root of this tree. Love8909 sends commands to inform cities to add soldiers. The command, being same to those of the ancients, with two values, X and K, means sending K soldiers to City X, sending K+1 soldiers to sons of City X, sending K+2 soldiers to sons of sons of City X and so on. Initially there are no soldiers in any city.

Love8909 may adjust the arrangement of soldiers ever and again. He asks questions about how many soldiers in the subtree rooted at City X. A subtree rooted at City X includes City X itself and all of its descendants. As Love8909‘s military counselor, you are responsible to complete all his commands and answer his questions.

Input

The first line of the input will be an integer T (T≤20) indicating the number of cases.

For each case, the first line contains two integers: N P, representing the number of cities in A230 and number of operations given by love8909.

The next line lists N−1 integers, in which the ith number, denoted as Xi+1, represents there is a road from City Xi+1 to City i+1. Note that the City 1has been omitted. 1≤Xi+1≤N for 2≤i≤N.

Then P lines follow, each gives an operation. Each operation belongs to either kind:

  • A X K. An adding-soldier command.
  • Q X. A question about how many soldiers in the subtree rooted at City X.

We guarantee that the cities form a rooted tree and the root is at City 1, which is the capital.

1≤N≤50000, 1≤P≤100000, 1≤X≤N, 0≤K≤1000.

Output

For each case, print Case #k: first in a single line, in which k represents the case number which starts from 1. Then for each Query X operation, print the answer in a single line.

Sample Input

1
7 10
1 1 2 2 5 5
Q 1
A 2 1
Q 1
Q 2
Q 5
A 5 0
Q 5
A 3 1
Q 1
Q 2

Sample Output

Case #1:
0
11
11
8
10
14
13

HINT

题意

给你一棵以1为根的树,有两个操作

1.A x k,让x增加k,x的儿子增加k+1,x的孙子增加k+2....x的t代儿子增加k+t

2.Q x , 查询x的子树的权值和是多少

题解:

看到处理子树问题,很显然的dfs序

dfs离散之后,维护线段树区间和,区间更新

我们很容易看出,他的更新是和deep有关的,deep越深的,更新越大

那么我们对于每个节点i,先区间更新y-deep[x],然后再使得更新一次,使得每个节点i增加deep[i]就好了

这样每个属于x的子树的都更新了 y - deep[x] + deep[i]

代码:

#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;
#define maxn 100010
struct Node
{
    int l,r,d,val;
};
Node node[maxn];
vector<int>Q[maxn];
int TTT[maxn];
int cnt = 1;
void dfs(int x,int fa,int d)
{
    node[x].l = cnt;
    node[x].d = d;
    TTT[cnt]=x;
    cnt++;
    for(int i=0;i<Q[x].size();i++)
    {
        int v = Q[x][i];
        if(v==fa)continue;
        dfs(v,x,d+1);
    }
    node[x].r = cnt;
}
int d[maxn];
struct Seg
{
    typedef long long SgTreeDataType;
    struct treenode
    {
      int L , R  ;
      SgTreeDataType sum , lazy1 , lazy2;
    };

    treenode tree[maxn*4];

    inline void push_down(int o)
    {
        SgTreeDataType lazyval1 = tree[o].lazy1;
        SgTreeDataType lazyval2 = tree[o].lazy2;
        if(lazyval1==0&&lazyval2==0)return;
        int L = tree[o].L , R = tree[o].R;
        int mid = (L+R)/2;
        tree[2*o].lazy1+=lazyval1;tree[2*o].sum+=lazyval1*(mid-L+1);
        tree[2*o+1].lazy1+=lazyval1;tree[2*o+1].sum+=lazyval1*(R-mid);

        tree[2*o].lazy2+=lazyval2;tree[2*o].sum+=lazyval2*d[2*o];
        tree[2*o+1].lazy2+=lazyval2;tree[2*o+1].sum+=lazyval2*d[2*o+1];
        tree[o].lazy1 = tree[o].lazy2 = 0;
    }

    inline void push_up(int o)
    {
        tree[o].sum = tree[2*o].sum + tree[2*o+1].sum;
    }

    inline void build_tree(int L , int R , int o)
    {
        tree[o].L = L , tree[o].R = R,tree[o].sum = tree[o].lazy1 = tree[o].lazy2 = 0;
        if(L==R)
            d[o]=node[TTT[L]].d;
        if (R > L)
        {
            int mid = (L+R) >> 1;
            build_tree(L,mid,o*2);
            build_tree(mid+1,R,o*2+1);
            d[o]=d[o*2]+d[o*2+1];
        }
    }

    inline void updata1(int QL,int QR,SgTreeDataType v,int o)
    {
        int L = tree[o].L , R = tree[o].R;
        if (QL <= L && R <= QR)
        {
            tree[o].lazy1 += v;
            tree[o].sum += v * (R-L+1);
        }
        else
        {
            push_down(o);
            int mid = (L+R)>>1;
            if (QL <= mid) updata1(QL,QR,v,o*2);
            if (QR >  mid) updata1(QL,QR,v,o*2+1);
            push_up(o);
        }
    }

    inline void updata2(int QL,int QR,SgTreeDataType v,int o)
    {
        int L = tree[o].L , R = tree[o].R;
        if (QL <= L && R <= QR)
        {
            tree[o].lazy2+=v;
            tree[o].sum+=v*d[o];
        }
        else
        {
            push_down(o);
            int mid = (L+R)>>1;
            if (QL <= mid) updata2(QL,QR,v,o*2);
            if (QR >  mid) updata2(QL,QR,v,o*2+1);
            push_up(o);
        }
    }

    inline SgTreeDataType query(int QL,int QR,int o)
    {
        int L = tree[o].L , R = tree[o].R;
        if (QL <= L && R <= QR) return tree[o].sum;
        else
        {
            push_down(o);
            int mid = (L+R)>>1;
            SgTreeDataType res = 0;
            if (QL <= mid) res += query(QL,QR,2*o);
            if (QR > mid) res += query(QL,QR,2*o+1);
            push_up(o);
            return res;
        }
    }
}T;

int main()
{
    int t;scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        printf("Case #%d:\n",cas);
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=0;i<=n;i++)Q[i].clear(),node[i].val=0;
        cnt = 1;
        for(int i=2;i<=n;i++)
        {
            int x,y;scanf("%d",&x);
            y=i;
            Q[x].push_back(y);
            Q[y].push_back(x);
        }
        dfs(1,-1,1);
        T.build_tree(1,n,1);
        string ch;
        while(q--)
        {
            cin>>ch;
            if(ch[0]==‘Q‘)
            {
                int x;scanf("%d",&x);
                printf("%lld\n",T.query(node[x].l,node[x].r-1,1));
            }
            else
            {
                int x,y;scanf("%d%d",&x,&y);
                T.updata1(node[x].l,node[x].r-1,y-node[x].d,1);
                T.updata2(node[x].l,node[x].r-1,1,1);
            }
        }
    }
}
时间: 2024-10-01 07:40:02

cdoj 574 High-level ancients 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表示这个数在此区间中,

HDU 4366 Successor( DFS序+ 线段树 )

Successor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2631    Accepted Submission(s): 634 Problem Description Sean owns a company and he is the BOSS.The other Staff has one Superior.every st