首页 > 搜索 > DFS搜索 > HDU 3966-Aragorn’s Story-DFS-[解题报告]HOJ
2015
04-14

HDU 3966-Aragorn’s Story-DFS-[解题报告]HOJ

Aragorn’s Story

问题描述 :

Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges connect them. It is guaranteed that for any two camps, there is one and only one path connect them. At first Aragorn know the number of enemies in every camp. But the enemy is cunning , they will increase or decrease the number of soldiers in camps. Every time the enemy change the number of soldiers, they will set two camps C1 and C2. Then, for C1, C2 and all camps on the path from C1 to C2, they will increase or decrease K soldiers to these camps. Now Aragorn wants to know the number of soldiers in some particular camps real-time.

输入:

Multiple test cases, process to the end of input.

For each case, The first line contains three integers N, M, P which means there will be N(1 ≤ N ≤ 50000) camps, M(M = N-1) edges and P(1 ≤ P ≤ 100000) operations. The number of camps starts from 1.

The next line contains N integers A1, A2, …AN(0 ≤ Ai ≤ 1000), means at first in camp-i has Ai enemies.

The next M lines contains two integers u and v for each, denotes that there is an edge connects camp-u and camp-v.

The next P lines will start with a capital letter ‘I’, ‘D’ or ‘Q’ for each line.

‘I’, followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, increase K soldiers to these camps.

‘D’, followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, decrease K soldiers to these camps.

‘Q’, followed by one integer C, which is a query and means Aragorn wants to know the number of enemies in camp C at that time.

输出:

Multiple test cases, process to the end of input.

For each case, The first line contains three integers N, M, P which means there will be N(1 ≤ N ≤ 50000) camps, M(M = N-1) edges and P(1 ≤ P ≤ 100000) operations. The number of camps starts from 1.

The next line contains N integers A1, A2, …AN(0 ≤ Ai ≤ 1000), means at first in camp-i has Ai enemies.

The next M lines contains two integers u and v for each, denotes that there is an edge connects camp-u and camp-v.

The next P lines will start with a capital letter ‘I’, ‘D’ or ‘Q’ for each line.

‘I’, followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, increase K soldiers to these camps.

‘D’, followed by three integers C1, C2 and K( 0≤K≤1000), which means for camp C1, C2 and all camps on the path from C1 to C2, decrease K soldiers to these camps.

‘Q’, followed by one integer C, which is a query and means Aragorn wants to know the number of enemies in camp C at that time.

样例输入:

3 2 5
1 2 3
2 1
2 3
I 1 3 5
Q 2
D 1 2 2
Q 1 
Q 3

样例输出:

7
4
8
Hint
1.The number of enemies may be negative. 2.Huge input, be careful.

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题解:

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

#define MAXN 50010
#define L(u) (u<<1)
#define R(u) (u<<1|1)

//写在类里面爆栈
int n, m, q;
int tim;       //时间戳
int num[MAXN]; //树上每个节点的初始值
int siz[MAXN]; //siz[u]表示以u为根的子树的节点数
int top[MAXN]; //树链上深度最小的点
int son[MAXN]; //重儿子
int dep[MAXN]; //深度
int tid[MAXN]; //节点的时间戳
int _tid[MAXN]; //tid[i]=j表示时间戳为i的节点是j
int father[MAXN]; //父节点
bool vis[MAXN];
vector<int> edge[MAXN];

void init(int n)
{
    for(int i = 1; i <= n; i++)
    {
        siz[i] = top[i] = son[i] = 0;
        dep[i] = tid[i] = _tid[i] = father[i] = 0;
        vis[i] = false;
        tim = 0; //时间戳
        edge[i].clear();
    }
}

void addedge(int u, int v) //无根树加双向边
{
    edge[u].push_back(v);
    edge[v].push_back(u);
}

//树链剖分
void dfs1(int u, int pre)
{
    vis[u] = true;
    siz[u] = 1;
    father[u] = pre;
    dep[u] = dep[pre] + 1; //注意根节点比较特殊
    int sz = edge[u].size();
    for(int i = 0; i < sz; i++)
    {
        int v = edge[u][i];
        if(v != father[u] && vis[v] == false)
        {
            dfs1(v, u);
            siz[u] += siz[v];
            if(son[u] == 0) son[u] = v;
            else if(siz[son[u]] < siz[v]) son[u] = v;
        }
    }
}

void dfs2(int u, int tp)
{
    vis[u] = true;
    tid[u] = ++tim;
    _tid[tim] = u;
    top[u] = tp;
    if(son[u] != 0)
        dfs2(son[u], tp); //同一条重链的顶部相同

    int sz = edge[u].size();
    for(int i = 0; i < sz; i++)
    {
        int v = edge[u][i];
        if(v != father[u] && v != son[u] && vis[v] == false) //注意去掉重儿子
            dfs2(v, v);
    }
}

void update(int u, int l, int r, int v); //线段树的更新函数

void change(int x, int y, int val)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])
            swap(x, y);
        update(1, tid[top[x]], tid[x], val); //dfs2时顶部先访问,故tid[top]较小
        x = father[top[x]]; //因为top[x]->x路径上的所有点已经被更新了
    }

    if(dep[x] > dep[y]) //同一条重链上深度小的tid小
        swap(x, y);
    update(1, tid[x], tid[y], val);
}


//线段树部分
struct NODE {
    int l, r, val, lazy;
}node[MAXN*4];

void build(int u, int l, int r)
{
    node[u].l = l;
    node[u].r = r;
    node[u].lazy = node[u].val = 0;
    if(l == r)
    {
        node[u].val = num[_tid[l]];
        return;
    }

    int mid = (l + r) >> 1;
    build(L(u), l, mid);
    build(R(u), mid + 1, r);
}

void pushdown(int u)
{
    if(node[u].lazy != 0)
    {
        node[L(u)].val += node[u].lazy;
        node[R(u)].val += node[u].lazy;
        node[L(u)].lazy += node[u].lazy;
        node[R(u)].lazy += node[u].lazy;
        node[u].lazy = 0;
    }
}

void update(int u, int l, int r, int v)
{
    if(node[u].l == l && node[u].r == r)
    {
        node[u].val += v;
        node[u].lazy += v;
        return;
    }

    pushdown(u);
    int mid = (node[u].l + node[u].r) >> 1;
    if(r <= mid)
        update(L(u), l, r, v);
    else if(l > mid)
        update(R(u), l, r, v);
    else
    {
        update(L(u), l, mid, v);
        update(R(u), mid + 1, r, v);
    }
}

int query(int u, int x)
{
    if(node[u].l == x && node[u].r == x)
        return node[u].val;

    pushdown(u);
    int mid = (node[u].l + node[u].r) >> 1;
    if(x <= mid) return query(L(u), x);
    else return query(R(u), x);
}


int main()
{
    char oper[2];
    int a, b, c;
    while(scanf("%d%d%d",&n,&m,&q) != EOF)
    {
        init(n);

        for(int i = 1; i <= n; i++)
            scanf("%d", &num[i]);

        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d",&a, &b);
            addedge(a, b);
        }

        dfs1(1, 0);
        memset(vis, 0, sizeof(vis));
        dfs2(1, 1);
        build(1, 1, n);

        while(q--)
        {
            scanf("%s", oper);
            if(oper[0] == 'Q')
            {
                scanf("%d", &a);
                printf("%d\n", query(1, tid[a]));
            }
            else
            {
                scanf("%d%d%d", &a, &b, &c);
                if(oper[0] == 'I')
                    change(a, b, c);
                else
                    change(a, b, -c);
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

参考:http://blog.csdn.net/tsaid/article/details/8997079


, ,
  1. 学算法中的数据结构学到一定程度会乐此不疲的,比如其中的2-3树,类似的红黑树,我甚至可以自己写个逻辑文件系统结构来。

  2. Good task for the group. Hold it up for every yeara??s winner. This is a excellent oppotunity for a lot more enhancement. Indeed, obtaining far better and much better is constantly the crucial. Just like my pal suggests on the truth about ab muscles, he just keeps obtaining much better.