天天看点

hdoj 3966 Aragorn's Story 【树链剖分+线段树||树状数组】

题目链接;​​3966​​

题意:

有三种操作:

Q A

查找A营的士兵的人数

I A B C

在A-B这个区间中的所有营的士兵个数都增加C

D A B C

在A-B这个区间中的所有营的士兵个数都减少C

树链剖分模板题---

1》求出重链--

2》链接重链--

3》利用线段树--树状数组等解决问题---

线段树代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int MA=50500;
struct node{
  int to,next;
}edge[MA*2];
int n,m,q,pos,tot;
int head[MA];
int p[MA];
int fp[MA];
int top[MA];
int num[MA];
int deep[MA];
int fre[MA];
int son[MA];
int s[MA];
void init()
{
  tot=0;pos=1;
  memset(head,-1,sizeof(head));
  memset(son,-1,sizeof(son));
}
void addedge(int a,int b)
{
  edge[tot].to=b;
  edge[tot].next=head[a];
  head[a]=tot++;
}
//树链剖分 
void dfs(int xx,int fa,int de)//求出父结点--深度--子结点的个数 --重链 
{
  fre[xx]=fa;
  deep[xx]=de;
  num[xx]=1;
  for (int k=head[xx];k!=-1;k=edge[k].next)
  {
    int ac=edge[k].to;
    if (ac!=fa)
    {
      dfs(ac,xx,de+1);
      num[xx]+=num[ac];
      if (son[xx]==-1||num[ac]>num[son[xx]])
      son[xx]=ac;
    }
  }
}
void getpos(int x,int sp)//拉树成链 
{
  p[x]=pos;
  fp[pos]=x;
  pos++;
  top[x]=sp;
  if (son[x]==-1) return;
  getpos(son[x],sp); 
  for (int k=head[x];k!=-1;k=edge[k].next)
  {
    int ac=edge[k].to;
    if (ac!=son[x]&&ac!=fre[x])
    {
      getpos(ac,ac);
    }
  }
}
//线段树 
struct Node{
  int l,r,val;
}tree[MA*3];
void build(int l,int r,int pp)
{
  tree[pp].l=l;
  tree[pp].r=r;
  if (l==r)
  {
    tree[pp].val=s[fp[l]];
    return ;
  }
  tree[pp].val=0;
  int mid=(l+r)/2;
  build(l,mid,pp*2);
  build(mid+1,r,pp*2+1);
}
int ans;
void query(int xx,int pp)//求值-- 
{
  ans+=tree[pp].val;
  if (tree[pp].l==tree[pp].r)
  return ;
  int mid=(tree[pp].l+tree[pp].r)/2;
  if (xx<=mid) query(xx,pp*2);
  else query(xx,pp*2+1);
}
void update(int l,int r,int val,int pp)//更新 
{
  if (l<=tree[pp].l&&tree[pp].r<=r)
  {
    tree[pp].val+=val;
    return ;
  }
  int mid=(tree[pp].l+tree[pp].r)/2;
  if (r<=mid) update(l,r,val,pp*2);
  else if (l>mid) update(l,r,val,pp*2+1);
  else{
    update(l,mid,val,pp*2);
    update(mid,r,val,pp*2+1);
  }
}
void change(int a,int b,int val)//更新-- 
{
  int f1=top[a],f2=top[b];
  while (f1!=f2)
  {
    if (deep[f1]<deep[f2])
    {
      swap(f1,f2);
      swap(a,b);
    }
    update(p[f1],p[a],val,1);
    a=fre[f1];f1=top[a];
  }
  if (deep[a]>deep[b]) swap(a,b);
  update(p[a],p[b],val,1);
}
int main()
{
  while (~scanf("%d%d%d",&n,&m,&q))
  {
    for (int i=1;i<=n;i++)
    scanf("%d",&s[i]);
    char ch[5];
    int a,b,c,d;init();
    for (int i=0;i<m;i++)
    {
      scanf("%d%d",&a,&b);
      addedge(a,b);
      addedge(b,a);
    }
    dfs(1,0,0);
    getpos(1,0);
    build(1,n,1);
    while (q--)
    {
      scanf("%s%d",ch,&a);
      ans=0;
      if (ch[0]=='Q')
      {
        query(p[a],1);
        printf("%d\n",ans);
      }
      else
      {
        scanf("%d%d",&b,&c);
        if (ch[0]=='D')
        c=-c;
        change(a,b,c);
      }
    }
  }
  return 0;
}      

数组数组代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int MA=50500;
struct node{
  int to,next;
}edge[MA*2];
int n,m,q,pos,tot;
int head[MA];
int p[MA];
int fp[MA];
int top[MA];
int num[MA];
int deep[MA];
int fre[MA];
int son[MA];
int s[MA];
void init()
{
  tot=0;pos=1;
  memset(head,-1,sizeof(head));
  memset(son,-1,sizeof(son));
}
void addedge(int a,int b)
{
  edge[tot].to=b;
  edge[tot].next=head[a];
  head[a]=tot++;
}
//树链剖分 
void dfs(int xx,int fa,int de)//求出父结点--深度--子结点的个数 --重链 
{
  fre[xx]=fa;
  deep[xx]=de;
  num[xx]=1;
  for (int k=head[xx];k!=-1;k=edge[k].next)
  {
    int ac=edge[k].to;
    if (ac!=fa)
    {
      dfs(ac,xx,de+1);
      num[xx]+=num[ac];
      if (son[xx]==-1||num[ac]>num[son[xx]])
      son[xx]=ac;
    }
  }
}
void getpos(int x,int sp)//拉树成链 
{
  p[x]=pos;
  fp[pos]=x;
  pos++;
  top[x]=sp;
  if (son[x]==-1) return;
  getpos(son[x],sp); 
  for (int k=head[x];k!=-1;k=edge[k].next)
  {
    int ac=edge[k].to;
    if (ac!=son[x]&&ac!=fre[x])
    {
      getpos(ac,ac);
    }
  }
}
//树状数组 
int shu[MA];
void ADD(int xx,int val)
{
  for (;xx<=n+1;xx+=xx&-xx)
  shu[xx]+=val;
}
int Query(int xx)
{
  int lp=0;
  for (;xx>0;xx-=xx&-xx)
  lp+=shu[xx];
  return lp;
}
void change(int a,int b,int val)//更新-- 
{
  int f1=top[a],f2=top[b];
  while (f1!=f2)
  {
    if (deep[f1]<deep[f2])
    {
      swap(f1,f2);
      swap(a,b);
    }
    ADD(p[f1],val);
    ADD(p[a]+1,-val);
    a=fre[f1];f1=top[a];
  }
  if (deep[a]>deep[b]) swap(a,b);
  ADD(p[a],val);
  ADD(p[b]+1,-val);
}
int main()
{
  while (~scanf("%d%d%d",&n,&m,&q))
  {
    for (int i=1;i<=n;i++)
    scanf("%d",&s[i]);
    char ch[5];
    int a,b,c,d;init();
    for (int i=0;i<m;i++)
    {
      scanf("%d%d",&a,&b);
      addedge(a,b);
      addedge(b,a);
    }
    dfs(1,0,0);
    getpos(1,0);
    memset(shu,0,sizeof(shu));
    for (int i=1;i<=n;i++)
    {
      ADD(p[i],s[i]);
      ADD(p[i]+1,-s[i]);
    }
    while (q--)
    {
      scanf("%s%d",ch,&a);
      if (ch[0]=='Q')
      {
        printf("%d\n",Query(p[a]));
      }
      else
      {
        scanf("%d%d",&b,&c);
        if (ch[0]=='D')
        c=-c;
        change(a,b,c);
      }
    }
  }
  return 0;
}