HDU 5209 Relief grain 解題報告(樹鏈剖分 + 線段樹)

Relief grain

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)
Total Submission(s): 325    Accepted Submission(s): 76


Problem Description
The soil is cracking up because of the drought and the rabbit kingdom is facing a serious famine. The RRC(Rabbit Red Cross) organizes the distribution of relief grain in the disaster area.

We can regard the kingdom as a tree with n nodes and each node stands for a village. The distribution of the relief grain is divided into m phases. For each phases, the RRC will choose a path of the tree and distribute some relief grain of a certain type for every village located in the path.

There are many types of grains. The RRC wants to figure out which type of grain is distributed the most times in every village.
 

Input
The input consists of at most 25 test cases.

For each test case, the first line contains two integer n and m indicating the number of villages and the number of phases.

The following n-1 lines describe the tree. Each of the lines contains two integer x and y indicating that there is an edge between the x-th village and the y-th village.
  
The following m lines describe the phases. Each line contains three integer x, y and z indicating that there is a distribution in the path from x-th village to y-th village with grain of type z. (1 <= n <= 100000, 0 <= m <= 100000, 1 <= x <= n, 1 <= y <= n, 1 <= z <= 100000)

The input ends by n = 0 and m = 0.
 

Output
For each test case, output n integers. The i-th integer denotes the type that is distributed the most times in the i-th village. If there are multiple types which have the same times of distribution, output the minimal one. If there is no relief grain in a village, just output 0.
 

Sample Input
2 4 1 2 1 1 1 1 2 2 2 2 2 2 2 1 5 3 1 2 3 1 3 4 5 3 2 3 3 1 5 2 3 3 3 0 0
 

Sample Output
1 2 2 3 3 0 2
Hint
For the first test case, the relief grain in the 1st village is {1, 2}, and the relief grain in the 2nd village is {1, 2, 2}.
 

Source
 


    解題報告:題意很容易懂,不說啥了……

    這是BZOJ的原題,附VJ題目鏈接,不過暫時無法提交:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=48535

    廣州區域賽網絡賽的題目,比賽時不會做,比完後還是不會做……

    參考了某大牛的解題報告:http://blog.csdn.net/u013368721/article/details/39449273。說的非常詳細了。

    之前沒接觸過樹鏈剖分,現在算是熟悉了。通過對一顆樹按照兒子數量的多少,將樹分爲重鏈和輕鏈,從而達到快速訪問路徑的目的。

    即便路徑上的都是輕鏈,那麼這顆輕鏈的長度也不會超過log(節點數)的級別。(重鏈的兒子比輕鏈多,感覺上也是這樣)。

    將路徑切分爲多個重鏈,在重鏈的起始位置將z+1,結束位置z-1。中間使用線段樹統計,非常方便。

    代碼如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <cassert>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")

#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define df(m) while(m--)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define travel(e, u) for(int e = u, v = vv[u]; e; e = nxt[e], v = vv[e])
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
#endif // ACM

    work();
}

void scanf(int & x, char ch = 0)
{
    while((ch = getchar()) < '0' || ch > '9');
    x = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9') x = 10 * x + (ch - '0');
}

/***************************************************************************************/

const int maxv = 111111;
const int maxe = 2222222;

int m, n;

int ecnt, treeIdx;
int edge[maxv], num[maxv];
int vv[maxe], nxt[maxe];

int siz[maxv], dep[maxv], dad[maxv];
int son[maxv], pos[maxv], idx[maxv], top[maxv];

int ans[maxv];

#define ls (pos<<1)
#define rs (pos<<1|1)
#define root 1, 100000, 1
#define lson l, m, (pos<<1)
#define rson m+1, r, (pos<<1|1)
#define mid ((l+r)/2)

int real[maxv<<2];
int sum[maxv<<2];
int val[maxv<<2];

void init()
{
    ecnt = 2;
    treeIdx = 0;

    memset(edge, 0, sizeof(edge));
    memset(num, 0, sizeof(edge));

    memset(sum, 0, sizeof(sum));
}

void addEdge(int u, int v, int first[])
{
    nxt[ecnt] = first[u], vv[ecnt] = v, first[u] = ecnt++;
}

void dfs(int u)
{
    siz[u] = 1;
    son[u] = 0;

    travel(e, edge[u]) if(v != dad[u])
    {
        dep[v] = dep[u] + 1;
        dad[v] = u;

        dfs(v);

        siz[u] += siz[v];
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
}

void heavy(int u, int t)
{
    top[u] = t;
    pos[u] = ++treeIdx;
    idx[treeIdx] = u;

    if(son[u]) heavy(son[u], t);
    travel(e, edge[u]) if(v != dad[u] && v != son[u])
        heavy(v, v);
}

void mark(int x, int y, int v)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        addEdge(pos[top[x]], v, num);
        addEdge(pos[x] + 1, -v, num);
        x = dad[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    addEdge(pos[x], v, num);
    addEdge(pos[y]+1, -v, num);
}

void build(int l, int r, int pos)
{
    if(l == r)
    {
        real[l] = pos;
        val[pos] = l;
        return;
    }

    int m = mid;
    build(lson);
    build(rson);
}

void update(int v, int pos)
{
    sum[pos] += v;

    while(pos > 1)
    {
        pos /= 2;

        if(sum[ls] >= sum[rs])
            sum[pos] = sum[ls], val[pos] = val[ls];
        else
            sum[pos] = sum[rs], val[pos] = val[rs];
    }
}

void work()
{
    build(root);

    while(scanf("%d%d", &n, &m) == 2 && (m || n))
    {
        init();

        ff(i, n-1)
        {
            int u, v;
            scanf(u);
            scanf(v);

            addEdge(u, v, edge);
            addEdge(v, u, edge);
        }

        dfs(1);
        heavy(1, 1);

        while(m--)
        {
            int u, v, w;
            scanf(u);
            scanf(v);
            scanf(w);

            mark(u, v, w);
        }

        fff(i, 1, n)
        {
            travel(e, num[i]) if(v > 0)
                update( 1, real[ v]);
            else
                update(-1, real[-v]);

            ans[idx[i]] = sum[1] ? val[1] : 0;
        }

        fff(i, 1, n) printf("%d\n", ans[i]);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章