您的位置:首页 > 编程语言 > Go语言

hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)

2016-03-23 14:54 519 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:

给出一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

D C1 C2 K:把C1与C2的路径上的所有点权值减去K

Q C:查询节点编号为C的权值

分析:

典型的树链剖分,对节点进行操作,可以用树状数组或者线段树。

树链剖分+树状数组:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;
const int maxn = 51000;

struct Edge
{
int to,next;
}edge[maxn*2];
int head[maxn],cnt,num;
int a[maxn],n,m,p,c[maxn];
int size[maxn],top[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn];

void init()
{
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
memset(c,0,sizeof(c));
cnt=0;
num=0;
}
void addedge(int u,int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}

void dfs_1(int u,int f,int d)
{
dep[u]=d;
size[u]=1;
fa[u]=f;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==f)
continue;
dfs_1(v,u,d+1);
size[u]+=size[v];
if(son[u]==-1||size[son[u]]<size[v])
son[u]=v;
}
}

void dfs_2(int u,int tp)
{
top[u] = tp;
id[u] = ++num;
if(son[u]!=-1)
dfs_2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u]||v==son[u])
continue;
dfs_2(v,v);
}
}

int lowbit(int x)
{
return x&-x;
}

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

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

void change(int u,int v,int val)
{
int tp1=top[u],tp2=top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
add(id[tp1],val);
add(id[u]+1,-val);
u=fa[tp1];
tp1=top[u];
}
if(dep[u]>dep[v])
swap(u,v);
add(id[u],val);
add(id[v]+1,-val);
}

int main()
{
while(~scanf("%d%d%d",&n,&m,&p))
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs_1(1,0,1);
dfs_2(1,1);
for(int i=1;i<=n;i++)
{
add(id[i],a[i]);
add(id[i]+1,-a[i]);
}
char s[5];
int c1,c2,k,c;
for(int i=0;i<p;i++)
{
scanf("%s",s);
if(s[0]=='I')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,k);
}
if(s[0]=='D')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,-k);
}
if(s[0]=='Q')
{
scanf("%d",&c);
cout<<sum(id[c])<<endl;
}
}
}
return 0;
}


树链剖分+线段树:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 51000;
int n,m,p;
int val[maxn],a[maxn];
struct Edge
{
int to,next;
}edge[maxn*2];
int head[maxn],add[maxn*4];
int dep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn];
int cnt,num;
void init()
{
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
memset(add,0,sizeof(add));
cnt=0;
num=0;
}

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

void dfs_1(int u,int f,int d)
{
dep[u]=d;
size[u]=1;
fa[u]=f;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==f)
continue;
dfs_1(v,u,d+1);
size[u]+=size[v];
if(son[u]==-1||size[son[u]]<size[v])
son[u]=v;
}
}

void dfs_2(int u,int tp)
{
top[u] = tp;
id[u] = ++num;
if(son[u]!=-1)
dfs_2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v = edge[i].to;
if(v == fa[u] ||v == son[u])
continue;
dfs_2(v,v);
}
}

struct Tree
{
int left,right;
int sum;
}tree[maxn*4];

void pushup(int i)
{
tree[i].sum = tree[i*2].sum + tree[i*2+1].sum;
}

void build(int i,int begin,int end)
{
tree[i].left=begin;
tree[i].right=end;
if(begin==end)
{
tree[i].sum=val[begin];
return;
}
int mid=(begin+end)/2;
build(i*2,begin,mid);
build(i*2+1,mid+1,end);
pushup(i);
}

void pushdown(int i)
{
if(add[i])
{
add[i*2] += add[i];
add[i*2+1] += add[i];
int mid=(tree[i].left+tree[i].right)/2;
tree[i*2].sum += add[i]*(mid-tree[i].left+1);
tree[i*2+1].sum += add[i]*(tree[i].right-mid);
add[i]=0;
}
}

void update(int i,int begin,int end,int value)
{
if(tree[i].left>=begin&&tree[i].right<=end)
{
add[i]+=value;
tree[i].sum+=value*(tree[i].right-tree[i].left+1);
return;
}
pushdown(i);
int mid=(tree[i].left+tree[i].right)/2;
if(mid>=begin)
update(i*2,begin,end,value);
if(mid<end)
update(i*2+1,begin,end,value);
pushup(i);
}

void change(int u,int v,int value)
{
int tp1=top[u],tp2=top[v];
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
update(1,id[tp1],id[u],value);
u = fa[tp1];
tp1 = top[u];
}
if(dep[u]>dep[v])
swap(u,v);
update(1,id[u],id[v],value);
}

long long query(int i,int begin,int end)
{
if(tree[i].left>=begin&&tree[i].right<=end)
return tree[i].sum;
pushdown(i);
int mid=(tree[i].left+tree[i].right)/2;
long long ans=0;
if(mid>=begin)
ans+=query(i*2,begin,end);
if(mid<end)
ans+=query(i*2+1,begin,end);
return ans;
}

int main()
{
while(~scanf("%d%d%d",&n,&m,&p))
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs_1(1,0,1);
dfs_2(1,1);

for(int i=1;i<=n;i++)
val[id[i]]=a[i];
build(1,1,n);
char s[5];
int c1,c2,k,c;
for(int i=0;i<p;i++)
{
scanf("%s",s);
if(s[0]=='I')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,k);
}
if(s[0]=='D')
{
scanf("%d%d%d",&c1,&c2,&k);
change(c1,c2,-k);
}
if(s[0]=='Q')
{
scanf("%d",&c);
cout<<query(1,id[c],id[c])<<endl;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: