传送门

题目描述

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.

题目大意

三种操作:

  • 点\(x\)到点\(y\)的路径上的每一个点的权值都+\(v\)
  • 点\(x\)到点\(y\)的路径上的每一个点的权值都-\(v\)
  • 查询点\(u\)的权值

解法

树链剖分的模板题,拿过来随便练练手。

我会在第4将的xio讲堂上详细讲解树剖,这里就稍微介绍一下。

树剖在沃的理解上,就是将一棵树通过dfs序或者其他的顺序,和轻重关系来展开到一个一位数组中,然后我们将各个在树上的操作变成一位的操作,这种操作就只需要用数据结构来维护就可以了。

那么反观这道题,我们就将树展开到一维上,并且用线段树来维护,其实非常好理解。

ac代码

#include<bits/stdc++.h>
#define ms(a,b) memset(a,b,sizeof(a))
#define N 50005
#define M 50005
using namespace std;
struct edge{
    int to,nt;
}E[M<<1];
int H[N],a[N],val[N],sz[N],dep[N],son[N],top[N],idx[N],fa[N];
int cnt,tot,n,m,p;
int read(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
void addedge(int u,int v){
    E[++cnt]=(edge){v,H[u]}; H[u]=cnt;
}
struct segment_tree{//线段树的各个操作,比较简单不多做讲解
    #define lson (nod<<1)
    #define rson (nod<<1|1)
    #define mid (l+r>>1)
    int tr[N<<2],add[N<<2];
    void init(){
        ms(tr,0);ms(add,0);
    }
    void pushup(int nod){
        tr[nod]=tr[lson]+tr[rson];
    }
    void pushdown(int l,int r,int nod){
        if(!add[nod]) return;
        tr[lson]+=add[nod]*(mid-l+1);
        tr[rson]+=add[nod]*(r-mid);
        add[lson]+=add[nod];
        add[rson]+=add[nod];
        add[nod]=0;
    }
    void build(int l,int r,int nod,int *a){
        if(l>=r){
            tr[nod]=a[l];
            return;
        }
        build(l,mid,lson,a);
        build(mid+1,r,rson,a);
        pushup(nod);
    }
    void update(int l,int r,int ql,int qr,int v,int nod){
        if(ql<=l&&r<=qr){
            tr[nod]+=v*(r-l+1);
            add[nod]+=v;
            return;
        }
        pushdown(l,r,nod);
        if(ql<=mid) update(l,mid,ql,qr,v,lson);
        if(qr>mid) update(mid+1,r,ql,qr,v,rson);
        pushup(nod);
    }
    int query(int l,int r,int k,int nod){
        if(l==r) return tr[nod];
        pushdown(l,r,nod);
        if(k<=mid) return query(l,mid,k,lson);
        else return query(mid+1,r,k,rson);
    }
}T;
void dfs1(int u,int ft,int dp){//第一遍dfs,求出sz,fa,dep。
    sz[u]=1;
    fa[u]=ft;
    dep[u]=dp;
    int maxson=-1;
    for(int e=H[u];e;e=E[e].nt){
        int v=E[e].to;
        if(v==fa[u]) continue;
        dfs1(v,u,dp+1);
        sz[u]+=sz[v];
        if(sz[v]>maxson) maxson=sz[v],son[u]=v;
    }
}
void dfs2(int u,int tp){//第二遍dfs,求出idx,val,top,和将各个重点连成重边
    idx[u]=++tot;
    val[tot]=a[u];
    top[u]=tp;
    if(!son[u]) return;
    dfs2(son[u],tp);
    for(int e=H[u];e;e=E[e].nt){
        int v=E[e].to;
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}
void init(){
    cnt=0,tot=0;
    ms(son,0);ms(E,0);ms(H,0);ms(top,0);ms(sz,0);ms(idx,0);ms(val,0);
}
int point_query(int u){return T.query(1,n,idx[u],1);}
void chain_update(int u,int v,int w){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        T.update(1,n,idx[top[u]],idx[u],w,1);
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    T.update(1,n,idx[u],idx[v],w,1);
}
int main(){
    while(~scanf("%d%d%d",&n,&m,&p)){
        T.init(); init();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=m;i++) {
            int u=read(),v=read();
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,-1,1);
        dfs2(1,1);
        T.build(1,n,1,val);
        while(p--){
            char opt[5];
            scanf("%s",opt);
            if(opt[0]=='Q'){
                int x=read();
                printf("%d\n",point_query(x));
            }
            if(opt[0]=='I'){
                int x=read(),y=read(),z=read();
                chain_update(x,y,z);
            }
            if(opt[0]=='D'){
                int x=read(),y=read(),z=read();
                chain_update(x,y,-z);
            }
        }
    }
    return 0;
}

[hdu3966]Aragorn's Story的更多相关文章

  1. 树链剖分入门-Hdu3966 Aragorn's Story

    AC通道:http://acm.hdu.edu.cn/showproblem.php?pid=3966 [题目大意] 一棵树上每个点有权值,每次支持三种操作:给[a,b]路径上的所有节点的权值加上k, ...

  2. hdu3966 Aragorn's Story 树链剖分

    题目传送门 题目大意: 有n个兵营形成一棵树,给出q次操作,每一次操作可以使两个兵营之间的所有兵营的人数增加或者减少同一个数目,每次查询输出某一个兵营的人数. 思路: 树链剖分模板题,讲一下树链剖分过 ...

  3. Aragorn's Story(hdu3966)

    题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K Q C:查询节点编号为C ...

  4. 【hdu3966】Aragorn's Story

    题意:给一棵树,并给定各个点权的值,然后有3种操作:I C1 C2 K: 把C1与C2的路径上的所有点权值加上KD C1 C2 K:把C1与C2的路径上的所有点权值减去KQ C:查询节点编号为C的权值 ...

  5. hdu3966 点权模板-树链部分

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. HDU 3966 Aragorn's Story (树链剖分+树状数组)

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  7. HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树

    HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...

  8. hdu 3966 Aragorn's Story 树链剖分 按点

    Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  9. HDU3966(树链剖分)

    题目:Aragorn's Story 题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有 ...

随机推荐

  1. java异步编程降低延迟

    目录 java异步编程降低延迟 一.ExecutorService和CompletionService 二.CompletableFuture(重要) 三.stream中的parallel(并行流) ...

  2. [转]zookeeper-端口说明

    一.zookeeper有三个端口(可以修改) 1.2181 2.3888 3.2888 二.3个端口的作用 1.2181:对cline端提供服务 2.3888:选举leader使用 3.2888:集群 ...

  3. ES6 Promise 异步操作

    最近越来越喜欢与大家进行资源分享了,并且及时的同步到自己的园子内,为什么呢? 一.小插曲(气氛搞起) 在上个月末,由于领导的高度重视(haha,这个高度是有多高呢,185就好了),走进了公司骨干员工的 ...

  4. Luogu P1337 [JSOI2004]平衡点 / 吊打XXX

    一道入门模拟退火的经典题,还是很考验RP的 首先我们发现神TM这道题又和物理扯上了关系,其实是一道求广义费马点的题目 首先我们可以根据物理知识得到,当系统处于平衡状态时,系统的总能量最小 又此时系统的 ...

  5. [Oracle]为何Archivelog 没有马上被删除

    [Oracle]为何Archivelog 没有马上被删除 客户设置了 Archivelog 的 deletion policy 是 CONFIGURE ARCHIVELOG DELETION POLI ...

  6. nginx解决前端跨域配置

    在nginx.conf文件中 添加如上配置: 在ajax中将原来的 url:http://192.168.1.127:8905/findItem 改成:'http://localhost/findIt ...

  7. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 场景模拟 接上一篇, JD SKU对应的店铺信息是异步加载 ...

  8. Vue Element Tabe Pager 分页方案

    表格和分页分离的,但是使用中,却是结合在一起的. 分析 有以下方式触发查询: mounted 加载数据. 查询按钮 加载数据. pager 变化加载数据 加载数据函数: loadData 问题 mou ...

  9. tableView优化思路

    一般优化的思路: 提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法. 复杂界面可采用异步绘制. 在大量图片展示时,可以滑动时按需加载. 尽量少用或不 ...

  10. 代码规范(RL-TOC)用更合理的方式写 JavaScript

    代码可以改变世界 不规范代码可以毁掉世界 只有先学会写规范的代码,才可以走的更远 编程语言之间有很多编程规范都是通用: 命名 不要用语言不明的缩写,不用担心名字过长,名字一定要让别人知道确切的意思; ...