HDU 3966 Aragorn's Story

先把树剖成链,然后用树状数组维护:

讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇...

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int MAXN = 50010;

struct Edge
{
    int to,next;
}edge[MAXN*2];

int head[MAXN],tot;
int top[MAXN];
int fa[MAXN];
int deep[MAXN];
int num[MAXN];
int p[MAXN];
int fp[MAXN];
int son[MAXN];
int pos;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 1;//使用树状数组,编号从头1开始
    memset(son,-1,sizeof(son));
}

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

void dfs1(int u,int pre,int d)
{
    deep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for(int i = head[u];i != -1; 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 != -1;i = edge[i].next)
    {
        int v = edge[i].to;
        if( v != son[u] && v != fa[u])
            getpos(v,v);
    }
}

//树状数组
int lowbit(int x)
{
    return x&(-x);
}

int c[MAXN];
int n;

int sum(int i)
{
    int s = 0;
    while(i > 0)
    {
        s += c[i];
        i -= lowbit(i);
    }
    return s;
}

void add(int i,int val)
{
    while(i <= n)
    {
        c[i] += val;
        i += lowbit(i);
    }
}

void Change(int u,int v,int val)//u->v的路径上点的值改变val
{
    int f1 = top[u], f2 = top[v];
    int tmp = 0;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        add(p[f1],val);
        add(p[u]+1,-val);
        u = fa[f1];
        f1 = top[u];
    }
    if(deep[u] > deep[v]) swap(u,v);
    add(p[u],val);
    add(p[v]+1,-val);
}

int a[MAXN];

int main()
{
    int M,P;
    while(scanf("%d%d%d",&n,&M,&P) == 3)
    {
        int u,v;
        int C1,C2,K;
        char op[10];
        init();
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
        }
        while(M--)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(1,0,0);
        getpos(1,1);
        memset(c,0,sizeof(c));

        for(int i = 1;i <= n;i++)
        {
            add(p[i],a[i]);
            add(p[i]+1,-a[i]);
        }
        while(P--)
        {
            scanf("%s",op);
            if(op[0] == 'Q')
            {
                scanf("%d",&u);
                printf("%d\n",sum(p[u]));
            }
            else
            {
                scanf("%d%d%d",&C1,&C2,&K);
                if(op[0] == 'D')
                    K = -K;
                Change(C1,C2,K);
            }
        }
    }
    return 0;
}
View Code

 

或者用线段树维护:

要注意,点权的时候,update函数里是不能 if (u == v) return;的。T_T

// HDU 3966

#include <stdio.h>
#include <string.h>
#include <iostream>
#define maxn 50010
#include <vector>
using namespace std;

int a[maxn];
vector<int> edge[maxn];

int pos;
int top[maxn];
int fa[maxn];
int deep[maxn];

int num[maxn];
int p[maxn];
int fp[maxn];
int son[maxn];

//树链剖分
void dfs1(int u, int pre, int d) { // fa num deep
    deep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for (int i=0; i<edge[u].size(); ++i) {
        int v = edge[u][i];
        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 dfs2(int u, int sp) {
    top[u] = sp;
    p[u] = pos++;
    fp[p[u]] = u;
    if (son[u] == -1) return;
    dfs2(son[u], sp);
    for (int i=0; i<edge[u].size(); ++i) {
        int v = edge[u][i];
        if (v != son[u] && v != fa[u])
            dfs2(v, v);
    }
}

//线段树
struct Node {
    int l, r;
    int val;
    int mark;
}segTree[maxn*3];

void build(int rt, int l, int r) {
    segTree[rt].l = l;
    segTree[rt].r = r;
    segTree[rt].mark = 0;
    segTree[rt].val = 0;
    if (l == r) {
        segTree[rt].val = a[fp[l] - 1];
        return;
    }
    int mid = (l + r) / 2;
    build(rt<<1, l, mid);
    build((rt<<1)|1, mid+1, r);
}

void push_down(int rt) {
    if (segTree[rt].mark != 0) {
        segTree[rt].val += segTree[rt].mark;
        if (segTree[rt].l != segTree[rt].r) {
            segTree[rt<<1].mark += segTree[rt].mark;
            segTree[(rt<<1)|1].mark += segTree[rt].mark;
        }
        segTree[rt].mark = 0;
    }
}

void update_seg(int rt, int l, int r, int val) { // 把线段树的[l, r] 区间的值+val
    push_down(rt);
    if (segTree[rt].l >= l && segTree[rt].r <= r) {
        segTree[rt].mark += val;
        push_down(rt);
        return;
    }
    int mid = (segTree[rt].l + segTree[rt].r) / 2;
    if (r <= mid) update_seg(rt<<1, l, r, val);
    else if (l > mid) update_seg((rt<<1)|1, l, r, val);
    else {
        update_seg(rt<<1, l, mid, val);
        update_seg((rt<<1)|1, mid+1, r, val);
    }
}

void update(int u, int v, int w) { // u 到 v结点的路上的值增加 val
    int f1 = top[u];
    int f2 = top[v];
    while(f1 != f2) {
        if (deep[f1] < deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        update_seg(1, p[f1], p[u], w);
        u = fa[f1], f1 = top[u];
    }
//    if (u == v) return;
    if (deep[u] > deep[v]) swap(u, v);
    update_seg(1, p[u], p[v], w);
}

int query_seg(int rt, int los) { //查询线段树 los处的值
    push_down(rt);
    if (segTree[rt].l == segTree[rt].r && segTree[rt].r == los) {
        return segTree[rt].val;
    }
    int mid = (segTree[rt].l + segTree[rt].r) / 2;
    if (los <= mid) return query_seg(rt<<1, los);
    else if (los > mid) return query_seg((rt<<1)|1, los);
}

int query(int u) { // 询问u点处的值
    return query_seg(1, p[u]);
}

int n;

void init() {
    pos = 0;
    memset(son, -1, sizeof(son));
    for (int i=1; i<=n; ++i) {
        edge[i].clear();
    }
}


int main() {
//    freopen("in.cpp", "r", stdin);
    int m, pp;
    while(~scanf("%d%d%d", &n, &m, &pp)) {
        init();
        for (int i=0; i<n; ++i) {
            scanf("%d", &a[i]);
        }
        for (int i=0; i<m; ++i) {
            int a, b;
            scanf("%d%d", &a, &b);
            edge[a].push_back(b);
            edge[b].push_back(a);
        }

        dfs1(1, 0, 1);
        dfs2(1, 1);
        build(1, 0, pos-1);

        for (int i=0; i<pp; ++i) {
            char op[10];
            int u, v, w;
            scanf("%s", op);
            if (op[0] == 'I' || op[0] == 'D') {
                scanf("%d%d%d", &u, &v, &w);
                if (op[0] == 'D') w = -w;
                update(u, v, w);
            }else {
                scanf("%d", &u);
                int ans = query(u);
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}
View Code

 

posted on 2016-11-08 19:38  小小八  阅读(170)  评论(0编辑  收藏  举报