HDU 5209 Relief grain 解题报告(树链剖分 + 线段树)

来源:互联网 发布:新速特软件站快优影音 编辑:程序博客网 时间:2024/04/29 17:23

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 41 21 1 11 2 22 2 22 2 15 31 23 13 45 32 3 31 5 23 3 30 0
 

Sample Output
1223302
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
2014 ACM/ICPC Asia Regional Guangzhou Online
 


    解题报告:题意很容易懂,不说啥了……

    这是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]);    }}


0 0
原创粉丝点击