HDU 3966(树链剖分+点修改+点查询)

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

题目大意:营地的分布成树型。每个营地都有一些人,每次修改修改一条链上的所有营地的人数,每次查询单个点。

解题思路

树链剖分基础题。

维护一个sum。

注意轻链修改时,点修改和边修改的不同。

由于树的结构与线段树点的顺序不太相同,因此需要做一个映射数组rank。故在线段树Build的时候,权值是camp[rank[l]],rank这步的映射在dfs2的时候完成,rank[w[u]]=u;

Query单点u的时候, w[u]是其在线段树中的位置。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include "cstdio"
#include "vector"
#include "cstring"
using namespace std;
#define maxn 50005
int camp[maxn],s[maxn],dep[maxn],pos[maxn],son[maxn],top[maxn],fa[maxn],w[maxn],rank[maxn],cnt,n;
vector<int> G[maxn];
void dfs1(int u,int pre,int d)
{
    s[u]=1;fa[u]=pre;dep[u]=d;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==pre) continue;
        dfs1(v,u,d+1);
        s[u]+=s[v];
        if(son[u]!=-1||s[v]>s[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int tp)
{
    w[u]=++cnt;top[u]=tp;rank[w[u]]=u;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
}
//Segment-Tree
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
int col[maxn<<2],sum[maxn<<2];
void PushUp(int root)
{
    sum[root]=sum[root<<1]+sum[root<<1|1];
}
void Build(int l,int r,int root)
{
    col[root]=0;
    if(l==r)
    {
        sum[root]=camp[rank[l]];
        return;
    }
    int mid=(l+r)>>1;
    Build(lson);
    Build(rson);
    PushUp(root);
}
void PushDown(int root,int m)
{
    if(col[root])
    {
        col[root<<1]+=col[root];
        col[root<<1|1]+=col[root];
        sum[root<<1]+=(m-(m>>1))*col[root];
        sum[root<<1|1]+=(m>>1)*col[root];
        col[root]=0;
    }
}
void Update(int L,int R,int v,int l,int r,int root)
{
    if(L<=l&&r<=R)
    {
        col[root]+=v;
        sum[root]+=(r-l+1)*v;
        return;
    }
    PushDown(root,r-l+1);
    int mid=(l+r)>>1;
    if(L<=mid) Update(L,R,v,lson);
    if(R>mid) Update(L,R,v,rson);
    PushUp(root);
}
int Query(int p,int l,int r,int root)
{
    if(l==r) return sum[root];
    PushDown(root,r-l+1);
    int mid=(l+r)>>1,ret=0;
    if(p<=mid) ret=Query(p,lson);
    else ret=Query(p,rson);
    return ret;
}
void Change(int x,int y,int v)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Update(w[top[x]],w[x],v,1,n,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    Update(w[x],w[y],v,1,n,1);//与边修改不同
}
int main()
{
    //freopen("in.txt","r",stdin);
    int m,p,u,v,c;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        memset(son,-1,sizeof(son));
        for(int i=0;i<=n;i++) G[i].clear();
        cnt=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&camp[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs1(1,1,1);
        dfs2(1,1);
        Build(1,n,1);
        char cmd[10];
        for(int i=1;i<=p;i++)
        {
            scanf("%s",&cmd);
            if(cmd[0]==‘I‘)
            {
                scanf("%d%d%d",&u,&v,&c);
                Change(u,v,c);
            }
            if(cmd[0]==‘D‘)
            {
                scanf("%d%d%d",&u,&v,&c);
                Change(u,v,-c);
            }
            if(cmd[0]==‘Q‘)
            {
                scanf("%d",&c);
                printf("%d\n",Query(w[c],1,n,1));
            }
        }
    }

}
11757337 2014-09-29 16:51:29 Accepted 3966 2484MS 8308K 3299 B C++ Physcal
时间: 2025-01-02 18:16:34

HDU 3966(树链剖分+点修改+点查询)的相关文章

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

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

POJ 2763 (树链剖分+边修改+边查询)

题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. 解题思路: 树链剖分基础题.每次Q之后改变一下s. 线段树记录的是边权.方法是对于一条边(u,v),边权值加在dep比较大的那一端. 链查询(边)和 链查询(点)在轻链时略有不同. 注意本题使用vector邻接表存图是会TLE的,应该使用链式前向星.树链剖分中使用链式前向星是基本要求. #inclu

hdu 3966 树链剖分第3遍

真心不好意思说话,写的越多,各种问题就暴漏出来了,这次更离谱,什么错误都有...不过还是过了.也明白了代码以后要写规范性,不能想当然... #include<cstdio> #include<cstring> #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> using namespace std;

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 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 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

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 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 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