hdu 5052 树链剖分

Yaoge’s maximum profit

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 982    Accepted Submission(s): 274

Problem Description

Yaoge likes to eat chicken chops late at night. Yaoge has eaten too many chicken chops, so that Yaoge knows the pattern in the world of chicken chops. There are N cities in the world numbered from 1 to N . There are some roads between some cities, and there is one and only one simple path between each pair of cities, i.e. the cities are connected like a tree. When Yaoge moves along a path, Yaoge can choose one city to buy ONE chicken chop and sell it in a city after the city Yaoge buy it. So Yaoge can get profit if Yaoge sell the chicken chop with higher price. Yaoge is famous in the world. AFTER Yaoge has completed one travel, the price of the chicken chop in each city on that travel path will be increased by V .

Input

The first line contains an integer T (0 < T ≤ 10), the number of test cases you need to solve. For each test case, the first line contains an integer N (0 < N ≤ 50000), the number of cities. For each of the next N lines, the i-th line contains an integer Wi(0 < Wi ≤ 10000), the price of the chicken chop in city i. Each of the next N - 1 lines contains two integers X Y (1 ≤ X, Y ≤ N ), describing a road between city X and city Y . The next line contains an integer Q(0 ≤ Q ≤ 50000), the number of queries. Each of the next Q lines contains three integer X Y V(1 ≤ X, Y ≤ N ; 0 < V ≤ 10000), meaning that Yaoge moves along the path from city X to city Y , and the price of the chicken chop in each city on the path will be increased by V AFTER Yaoge has completed this travel.

Output

For each query, output the maximum profit Yaoge can get. If no positive profit can be earned, output 0 instead.

Sample Input

1
5
1
2
3
4
5
1 2
2 3
3 4
4 5
5
1 5 1
5 1 1
1 1 2
5 1 1
1 2 1

Sample Output

4
0
0
1
0

/*
hdu 5052 树链剖分(nice)

problem:
给你一个树,每次找出u->v上面的最大差值(较小值必需在较大值前面).找出后在给路径所有点加上w

solve:
首先是线段树维护差值的问题,在这里错了很久- -. 按照以前的写习惯了,并没想区间合并时候的问题...
树链剖分查找的时候,每次只能查找一条链,所以在这里也要合并(右边链Max - 左边链Min).
而且u->v的话,因为u到(u,v)的lca的节点号是逆序的(根节点较小),所以线段树要维护 左到右and右到左的差值

hhh-2016-08-22 10:53:40
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#define lson  i<<1
#define rson  i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define key_val ch[ch[root][1]][0]
#define inf 0x3FFFFFFFFFFFFFFFLL
using namespace std;
const int maxn = 200100;
int head[maxn],tot,pos,son[maxn];
int top[maxn],fp[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn];
int n;
ll a[maxn];

ll MAX(ll a,ll b)
{
    return a>b?a:b;
}
ll MIN(ll a,ll b)
{
    return a>b?b:a;
}
struct Edge
{
    int to,next;
} edge[maxn<<2];

void ini()
{
    tot = 0,pos = 1;
    clr(head,-1),clr(son,-1);
}

void add_edge(int u,int v)
{
    edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;
}

void dfs1(int u,int pre,int d)
{
//    cout << u << " " <<pre <<" " <<d <<endl;
    dep[u] = d;
    fa[u] = pre,num[u] = 1;
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v != pre)
        {
            dfs1(v,u,d+1);
            num[u] += num[v];
            if(son[u] == -1 || num[v] > num[son[u]])
                son[u] = v;
        }
    }
}

void getpos(int u,int sp)
{
    top[u] = sp;
    p[u] = pos++;
    fp[p[u]] = u;
    if(son[u] == -1)return ;
    getpos(son[u],sp);
    for(int i = head[u]; ~i ; i = edge[i].next)
    {
        int v = edge[i].to;
        if(v != son[u] && v != fa[u])
            getpos(v,v);
    }
}

struct node
{
    int l,r,mid;
    ll Max,Min;
    ll lans,rans;
    ll add;
} tree[maxn << 2];

void push_up(int i)
{
    tree[i].Max = MAX(tree[lson].Max,tree[rson].Max);
    tree[i].Min = MIN(tree[lson].Min,tree[rson].Min);
    tree[i].rans = MAX(tree[rson].Max - tree[lson].Min,MAX(tree[lson].rans,tree[rson].rans));
    tree[i].lans = MAX(tree[lson].Max - tree[rson].Min,MAX(tree[lson].lans,tree[rson].lans));
    if(tree[i].lans < 0) tree[i].lans = 0;
    if(tree[i].rans < 0) tree[i].rans = 0;
}

void build(int i,int l,int r)
{
    tree[i].l = l,tree[i].r = r;
    tree[i].mid=(l+r) >>1;
    tree[i].add = 0;
    tree[i].Max = 0,tree[i].Min = inf;
    tree[i].lans = 0,tree[i].rans = 0;
    if(l == r)
    {
        tree[i].Max = tree[i].Min = a[fp[l]];
        return;
    }
    build(lson,l,tree[i].mid);
    build(rson,tree[i].mid+1,r);
    push_up(i);
}
void update(int i,ll d)
{
    tree[i].Max += d,tree[i].Min += d;
    tree[i].add += d;
}

void push_down(int i)
{
    if(tree[i].add)
    {
        update(lson,tree[i].add),update(rson,tree[i].add);
        tree[i].add = 0;
    }
}

void update_area(int i,int l,int r,ll val)
{
    if(tree[i].l >= l && tree[i].r <= r)
    {
        update(i,val);
        return ;
    }
    push_down(i);
    int mid = tree[i].mid;
    if(l <= mid)
        update_area(lson,l,r,val);
    if(r > mid)
        update_area(rson,l,r,val);
    push_up(i);
}

ll query(int i,int l,int r,int flag,ll& MaxPrice,ll& MinPrice)
{
    if(tree[i].l >= l && tree[i].r <= r)
    {
        MinPrice = tree[i].Min;
        MaxPrice = tree[i].Max;
        if(flag)
        {

            return tree[i].rans;
        }
        else
        {
            return tree[i].lans;
        }
    }
    push_down(i);
    int mid = tree[i].mid;
    if(r <= mid)
        return MAX(0LL,query(lson,l,r,flag,MaxPrice,MinPrice));
    else if(l > mid)
        return MAX(0LL,query(rson,l,r,flag,MaxPrice,MinPrice));
    else
    {
        ll ta = 0;
        ll max1,max2,min1,min2;
        ll ans = MAX(query(lson,l,mid,flag,max1,min1),query(rson,mid+1,r,flag,max2,min2));
        if(flag)
            ta = max2 - min1;
        else
            ta = max1 - min2;
        MaxPrice = MAX(max1,max2);
        MinPrice = MIN(min1,min2);
        ta = MAX(ta,0LL);
        return MAX(ans,ta);
    }
    push_up(i);
}

void make_add(int u,int v,ll val)
{
    int f1 = top[u],f2 = top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(f1,f2),swap(u,v);
        }
        update_area(1,p[f1],p[u],val);
        u = fa[f1],f1 = top[u];
    }
    if(dep[u] > dep[v])
        swap(u,v);
    update_area(1,p[u],p[v],val);
    return ;
}

ll make_query(int u,int v)
{
    ll tmin,tmax,tMin,tMax;
    ll cmin,cmax,cMin,cMax;
    tMin = tmin = tree[1].Max;
    tMax = tmax =  0;
    ll cnt = 0;
    int f1 = top[u],f2 = top[v];
    while(f1 != f2)
    {
        if(dep[f1] > dep[f2])
        {
//            cout << p[f1] <<" "<<p[u] <<endl;
            cnt = MAX(cnt,query(1,p[f1],p[u],0,cmax,cmin));
            cnt = MAX(cnt,cmax - tmin);
            cnt = MAX(cnt,tMax - cmin);
            tmin = MIN(cmin,tmin);
            tmax = MAX(cmax,tmax);
            u = fa[f1],f1 = top[u];
            //  tmax = max(tmax,cmax);
        }
        else
        {
//             cout << p[f2] <<" "<<p[v] <<endl;
            cnt = MAX(cnt,query(1,p[f2],p[v],1,cMax,cMin));
            cnt = MAX(cnt,tMax - cMin);
            cnt = MAX(cnt,cMax-tmin);
            tMax = MAX(tMax,cMax);
            tMin = MIN(tMin,cMin);
            v = fa[f2],f2 = top[v];
            // tMin = min(tMin,cMin);
        }
    }
    if(dep[u] > dep[v])
    {
        cnt =MAX(cnt,query(1,p[v],p[u],0,cmax,cmin));
        cnt =MAX(cnt,cmax-tmin);
        tmin = MIN(tmin,cmin);
        cnt = MAX(cnt,tMax-tmin);
    }
    else
    {
        cnt =MAX(cnt,query(1,p[u],p[v],1,cMax,cMin));
//        cout <<"max" <<cMax <<" " <<"min" <<cMin <<endl;
        cnt = MAX(cnt,tMax-cMin);
        tMax = MAX(tMax,cMax);
        cnt = MAX(cnt,tMax-tmin);
    }
    return cnt;
}

/*
5
3 1 1 1
1 2 2 3
3
1 1 500000000
2 1 1
3 1 1
*/
int main()
{
//    freopen("in.txt","r",stdin);
    int T;
    int m,u,v;
    ll w;
    scanf("%d",&T);
    while(T--)
    {
        ini();
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
            scanf("%I64d",&a[i]);
        for(int i =1; i <n; i++)
        {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,1,pos-1);
        scanf("%d",&m);
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d%I64d",&u,&v,&w);
            printf("%I64d\n",make_query(u,v));
            make_add(u,v,w);
        }
    }
    return 0;
}

  

时间: 2024-12-26 13:03:51

hdu 5052 树链剖分的相关文章

hdu 5893 (树链剖分+合并)

List wants to travel Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 429    Accepted Submission(s): 92 Problem Description A boy named List who is perfect in English. Now he wants to travel an

hdu 5242 树链剖分找权值最大的前k条链

http://acm.hdu.edu.cn/showproblem.php?pid=5242 Problem Description It is well known that Keima Katsuragi is The Capturing God because of his exceptional skills and experience in ''capturing'' virtual girls in gal games. He is able to play k games sim

hdu 5274 树链剖分

Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1484    Accepted Submission(s): 347 Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes

hdu 4897 树链剖分(重轻链)

Little Devil I Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 894    Accepted Submission(s): 296 Problem Description There is an old country and the king fell in love with a devil. The devil

HDU 3966 (树链剖分+线段树)

Problem Aragorn's Story (HDU 3966) 题目大意 给定一颗树,有点权. 要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值. 解题分析 树链剖分模板题. 实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的. 树链剖分的两个性质(转): 性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v]: 性质2:从根到某一点的路径上轻链.重链的个数都不大于logn. 保证了一个区间的时间复杂度是log2(n).

HDU 5274(树链剖分)

树链剖分第一题QAQ,纪念下 #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; const int maxn = 1e5 + 10; #define

HDU 5029 树链剖分

Relief grain Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submission(s): 861    Accepted Submission(s): 219 Problem Description The soil is cracking up because of the drought and the rabbit kingdom is f

hdu 3804树链剖分+离线操作

/* 树链刨分+离线操作 题意:给你一棵树,和询问x,y 从节点x--节点1的小于等于y的最大值. 解:先建一个空树,将树的边权值从小到大排序,将询问y按从小到大排序 对于每次询问y将小于等于y的边权值的边加入,在进行询问将结果储存最后输出即可 易错点:要考虑到节点1到节点1的情况需特判. */ #pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #include<string

HDU 5405 (树链剖分+线段树)

Problem Sometimes Naive 题目大意 给你一棵n个节点的树,有点权. 要求支持两种操作: 操作1:更改某个节点的权值. 操作2:给定u,v, 求 Σw[i][j]   i , j 为任意两点且i到j的路径与u到v的路径相交. 解题分析 容易发现对于一个询问,答案为总点权和的平方 减去 去掉u--v这条链后各个子树的点权和的平方的和. 开两棵线段树,tag1记录点权和,tag2记录某点的所有轻链子树的点权和的平方的和. 每次沿着重链往上走时,直接加上这条重链的所有点的tag2和