码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 3699 Aragorn's Story(树链剖分)

时间:2015-08-16 14:59:41      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:

题意:一棵树,已知每个节点的值和连接关系,

       三种操作:

       I x y k将x,y间的节点的值加k;

       D x y k将x,y间节点的值减k;

       Q x查询修改后x的值;

参考:http://blog.csdn.net/pi9nc/article/details/27316879

http://blog.csdn.net/acdreamers/article/details/10594121

http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

思路:对于树上的修改查询操作,采用树链剖分;

        主要思路是建树时找重边,再将重边链接成重链;

        修改时判断区间端点是否在同一重链上,若不在,则类似于lcm靠拢;若在同一重链,直接修改;

树状数组写法:

技术分享
#pragma comment(linker,"/STACK:1024000000,1024000000") //防爆栈
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
  int to,next;
}edge[500010];
int a[500010],c[500010];
int n;
int head[500010],tot;
int top[500010];  //重链的顶部节点
int fa[500010];   //父节点
int deep[500010]; //节点的度
int num[500010];  //以该节点为根的子树的节点数
int p[500010],fp[500010]; //在树上的编号,树上某编号对应的数
int son[500010],pos; //重儿子
void init(){
  tot=0;
  memset(head,-1,sizeof(head));
  pos=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 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){
    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 main(){
   int i,j,k,u,v;
   int x,y,z,m,P;
   while(scanf("%d%d%d",&n,&m,&P)!=EOF){
       char ch[12];
       init();
      for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
      }
      for(i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
      }
      dfs1(1,0,0);  //计算子树大小,节点的度,寻找重儿子
      getpos(1,1);  //将重边连接成重链
      memset(c,0,sizeof(c));
      for(i=1;i<=n;i++){  //树状数组建树
        add(p[i],a[i]);
        add(p[i]+1,-a[i]);
      }
      while(P--){
        scanf("%s",ch);
        if(ch[0]==Q){
            scanf("%d",&x);
            printf("%d\n",sum(p[x]));
        }
       else if(ch[0]==D){
            scanf("%d%d%d",&x,&y,&z);
            change(x,y,-z);
        }
        else{
            scanf("%d%d%d",&x,&y,&z);
            change(x,y,z);
        }
      }
   }
   return 0;
}
View Code

线段树写法:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>

using namespace std;
const int N=50010;

int n,m,Q;
int tim;

int num[N],siz[N],top[N],son[N];
int dep[N],tid[N],ran[N],fa[N];
int head[N],to[2*N],nex[2*N],edge;

void Init()
{
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
    tim=0;
    edge=0;
}

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

//树链剖分部分
void dfs1(int u,int father,int d)
{
    dep[u]=d;
    fa[u]=father;
    siz[u]=1;
    for(int i=head[u];~i;i=nex[i])
    {
        int v=to[i];
        if(v!=father)
        {
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if(son[u]==-1||siz[v]>siz[son[u]])
                son[u]=v;
        }
    }
}

void dfs2(int u,int tp)
{
    top[u]=tp;
    tid[u]=++tim;
    ran[tid[u]]=u;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=head[u];~i;i=nex[i])
    {
        int v=to[i];
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
}

//线段树部分
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

int sum[4*N],col[4*N];

void PushUP(int rt)
{
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}

void PushDown(int rt,int m)
{
    if(col[rt])
    {
        col[rt<<1]+=col[rt];
        col[rt<<1|1]+=col[rt];
        sum[rt<<1]+=(m-(m>>1))*col[rt];
        sum[rt<<1|1]+=(m>>1)*col[rt];
        col[rt]=0;
    }
}

void Build(int l,int r,int rt)
{
    col[rt]=0;
    if(l==r)
    {
        sum[rt]=num[ran[l]];
        return;
    }
    int mid=(l+r)>>1;
    Build(lson);
    Build(rson);
    PushUP(rt);
}

void Update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        col[rt]+=v;
        sum[rt]+=v*(r-l+1);
        return;
    }
    PushDown(rt,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(rt);
}

int Query(int l,int r,int rt,int val)
{
    if(l==r)
        return sum[rt];
    PushDown(rt,r-l+1);
    int mid=(l+r)>>1;
    int ret=0;
    if(val<=mid) ret=Query(lson,val);
    else         ret=Query(rson,val);
    PushUP(rt);
    return ret;
}

void Change(int x,int y,int val)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Update(tid[top[x]],tid[x],val,1,n,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    Update(tid[x],tid[y],val,1,n,1);
}

int main()
{
    char oper[5];
    int a,b,c;
    while(~scanf("%d%d%d",&n,&m,&Q))
    {
        Init();
        for(int i=1;i<=n;i++)
           scanf("%d",&num[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        dfs1(1,0,0);
        dfs2(1,1);
        Build(1,n,1);
        while(Q--)
        {
            scanf("%s",oper);
            if(oper[0]==Q)
            {
                scanf("%d",&a);
                printf("%d\n",Query(1,n,1,tid[a]));
            }
            else
            {
                scanf("%d%d%d",&a,&b,&c);
                if(oper[0]==D) c=-c;
                Change(a,b,c);
            }
        }
    }
    return 0;
}

 

hdu 3699 Aragorn's Story(树链剖分)

标签:

原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4734243.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!