hdu3966 树链剖分(区间更新和单点求值)

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

Problem Description

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.

Input

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.

Output

For each query, you need to output the actually number of enemies in the specified camp.

Sample Input

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

Sample Output

7
4
8

Hint

1.The number of enemies may be negative.

2.Huge input, be careful. 
/**
hdu3966  树链剖分(区间更新和单点求值)
题目大意:给定一棵树,对指定的连点之间的点的权进行更新,过程中询问指定点的当前值
解题思路:树链剖分,区间更新维护的题目
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=50005;
typedef long long LL;
int n,m,q,z;
LL a[maxn],sum[maxn*4],col[maxn*4];
int fa[maxn],Hash[maxn],dep[maxn],son[maxn],siz[maxn];
int num[maxn],top[maxn];

int head[maxn],ip;

void init()
{
    memset(head,-1,sizeof(head));
    memset(col,0,sizeof(col));
    memset(sum,0,sizeof(sum));
    ip=0;
}

struct note
{
    int v,next;
}edge[maxn*4];

void addedge(int u,int v)
{
    edge[ip].v=v,edge[ip].next=head[u],head[u]=ip++;
}

void dfs(int u,int pre)
{
    son[u]=0,siz[u]=1,dep[u]=dep[pre]+1,fa[u]=pre;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        dfs(v,u);
        if(siz[son[u]]<siz[v])
        {
            son[u]=v;
        }
        siz[u]+=siz[v];
    }
    ///printf("%d fa,dep,siz,son %d %d %d %d\n",u,fa[u],dep[u],siz[u],son[u]);
}

void set_que(int u,int tp)
{
    top[u]=tp,num[u]=++z,Hash[z]=u;
    if(son[u])
    {
        set_que(son[u],tp);
    }
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fa[u]||v==son[u])continue;
        set_que(v,v);
    }
  ///  printf("%d top num %d %d\n",u,top[u],num[u]);
}

void push_up(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
}
void build(int root,int l,int r)
{
    col[root]=0;
    if(l==r)
    {
        sum[root]=a[Hash[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    push_up(root);
}

void push_down(int root,int len)
{
    if(col[root])
    {
        col[root<<1]+=col[root];
        col[root<<1|1]+=col[root];
        sum[root<<1]+=col[root]*(len-(len>>1));
        sum[root<<1|1]+=col[root]*(len>>1);
        col[root]=0;
    }
}
void update(int root,int l,int r,int x,int y,int z)
{
    if(l>y||r<x)return;
    if(x<=l&&r<=y)
    {
        col[root]+=z;
        sum[root]+=(r-l+1)*z;
        return;
    }
    push_down(root,r-l+1);
    int mid=(l+r)>>1;
    update(root<<1,l,mid,x,y,z);
    update(root<<1|1,mid+1,r,x,y,z);
    push_up(root);
}
LL query(int root,int l,int r,int loc)
{
    if(l>loc||r<loc)return 0;
    if(l==r)
    {
        return sum[root];
    }
    push_down(root,r-l+1);
    int mid=(l+r)>>1;
    if(loc<=mid)
        return query(root<<1,l,mid,loc);
    else
        return query(root<<1|1,mid+1,r,loc);
}
int main()
{
   //freopen("data.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
        }
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        int root=(n+1)>>1;
        z=0,dep[0]=0,siz[0]=0;
        dfs(root,0);
        set_que(root,root);
        build(1,1,z);
        while(q--)
        {
            char s[20];
            int x,y,zz;
            scanf("%s",s);
            if(s[0]=='Q')
            {
                scanf("%d",&x);
                printf("%I64d\n",query(1,1,z,num[x]));
            }
            else
            {
                scanf("%d%d%d",&x,&y,&zz);
                if(s[0]=='D')zz=-zz;
                int f1=top[x],f2=top[y];
                while(f1!=f2)
                {
                    if(dep[f1]<dep[f2])
                    {
                        swap(f1,f2);
                        swap(x,y);
                    }
                    update(1,1,z,num[f1],num[x],zz);
                    x=fa[f1],f1=top[x];
                }
                if(dep[x]>dep[y])
                {
                    swap(x,y);
                }
                update(1,1,z,num[x],num[y],zz);
            }
        }
    }
    return 0;
}
时间: 2024-09-30 11:01:53

hdu3966 树链剖分(区间更新和单点求值)的相关文章

hdu3966 树链剖分+线段树 裸题

HDU - 3966 题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c 思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射):第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

bzoj2243树链剖分+区间合并

树链上区间合并的问题比区间修改要复杂,因为每一条重链在线段树上分布一般都是不连续的,所以在进行链上操作时要手动将其合并起来,维护两个端点值 处理时的方向问题:lca->u是一个方向,lca->v是另一个方向,到最后合并这两个放向时都看左端点即可 #include<cstring> #include<string> #include<iostream> #include<queue> #include<cstdio> #include&

hdu--3966(树链剖分)

题目链接:hdu--3966 给出n个点的值,还有n-1条边的连接方式,三种操作: 1.I在节点a到b的路径中所有的点都增加x 2.D在节点a到b的路径中所有的点都减少x 3.Q询问第k个节点的值. 将每个节点的值转化为父节点到子节点的边的权值,对于根节点做一个虚拟的父节点0 .进行树链剖分,整合到线段树中之后注意: 更新时,不能只更新a到b上的边的权值,因为那样会使b节点的权值不能被更新到,在更新a到b的段的权值后,应该在更新b到b的权值. #include <cstdio> #includ

(树链剖分+区间合并)HYSBZ - 2243 染色

题意: 两个操作: 1.把一条树链上的所有点权值变为w. 2.查询一条树链上有多少个颜色段 分析: 一看就是区间合并,做这到题首先需要一定的区间合并基础, 不过这题合并这部分在线段树区间合并中已经算是非常的简单的了. 线段树部分没有难度. 那么难点在于,在往LCA上走的时候,我们如何进行区间合并. 本来我想着, 在向上走的时候顺便进行区间判断并且合并,但是似乎有问题. 其实,可以将两步分开,先算出区间没合并之前的颜色段数,再次进行Top,判断颜色是否相等,相等就减掉. 代码: 1 #includ

POJ - 2155 Matrix (二维树状数组 + 区间改动 + 单点求值 或者 二维线段树 + 区间更新 + 单点求值)

POJ - 2155 Matrix Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we ha

专题训练之树链剖分

推荐几个博客:https://blog.csdn.net/y990041769/article/details/40348013 树链剖分详解 https://blog.csdn.net/ACdreamers/article/details/10591443 树链剖分原理 1.(HDOJ3966)http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值

CSUST 2012 一个顶俩 (本校OJ题)(思维+树链剖分)

(点击这里查看原题,不保证可以进去....外网可能比较卡) Description A:一心一意 B:一个顶俩 最近QQ更新后那个成语接龙好像挺火的?但我只知道图论里一条边是一个顶俩个点的emm. 如果我给你一个n个点n-1条边的无向联通图,但是这里头有一些边是脆弱的.随时都面临崩坏的危险. 为了维持他们的连通性,善良的我又给了你m条紫水晶备用边(u,v).我这里准备Q个问题,第i个问题为一个整数z(1≤z≤n−1)表示若第z条边崩坏了,你能选出多少条备用边保证图继续保持联通. Input 第一

poj 2763 树链剖分(单点更新,区间求值)

http://poj.org/problem?id=2763 Description After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional ro