标签:树链剖分
3 2 5 1 2 3 2 1 2 3 I 1 3 5 Q 2 D 1 2 2 Q 1 Q 3
7 4 8Hint1.The number of enemies may be negative. 2.Huge input, be careful.
题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可,注意HDU的OJ采用Windows系统,容易爆栈,所以在代码
前面加上:#pragma comment(linker, "/STACK:1024000000,1024000000")进行手动扩栈。
#pragma comment(linker, "/STACK:1024000000,1024000000") //因OJ采用Windows系统,要加入这一行用于 进行手动扩栈,这样就不会引起爆栈
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
const int N = 50015;
vector<int>mapt[N];
int fath[N],deep[N],top[N],num[N],son[N],p[N],pos;
void init(int n)
{
pos=0;
//memset(son,-1,sizeof(son));
for(int i=0;i<=n;i++)
mapt[i].clear();
}
void dfs(int u,int pre,int d)
{
fath[u]=pre; num[u]=1; deep[u]=d; son[u]=-1;
int k=mapt[u].size();
for(int i=k-1;i>=0;--i)
{
int v=mapt[u][i];
if(v==pre)continue;
dfs(v,u,d+1);
num[u]+=num[v];
if(son[u]==-1||num[son[u]]<num[v])
son[u]=v;
}
}
void getpos(int u,int root)
{
top[u]=root;
p[u]=++pos;//从1开始
if(son[u]==-1)
return ;
getpos(son[u],root);
int k=mapt[u].size();
for(int i=k-1;i>=0;--i)
{
int v=mapt[u][i];
if(son[u]==v||v==fath[u])
continue;
getpos(v,v);
}
}
struct tree
{
int allnum,addnum;
}root[N*3];
int a[N];
void build(int l,int r,int k)
{
root[k].addnum=0;
if(l==r){
root[k].allnum=a[l]; return ;
}
int mid=(l+r)/2;
build(l,mid,k<<1);
build(mid+1,r,(k<<1)|1);
root[k].allnum=root[k<<1].allnum+root[(k<<1)|1].allnum;
}
void upson(int l,int r,int k)
{
int mid=(l+r)/2;
if(root[k].addnum){
root[k<<1].allnum+=(mid-l+1)*root[k].addnum;
root[k<<1].addnum+=root[k].addnum;
root[(k<<1)|1].allnum+=(r-mid)*root[k].addnum;
root[(k<<1)|1].addnum+=root[k].addnum;
root[k].addnum=0;
}
}
void update(int l,int r,int k,int L,int R,int c)
{
if(L<=l&&r<=R)
{
root[k].allnum+=(r-l+1)*c; root[k].addnum+=c; return ;
}
int mid=(l+r)/2;
upson(l,r,k);
if(L<=mid) update(l,mid,k<<1,L,R,c);
if(mid<R) update(mid+1,r,(k<<1)|1,L,R,c);
root[k].allnum=root[k<<1].allnum+root[(k<<1)|1].allnum;
}
int query(int l,int r,int k,int id)
{
if(l==r)
return root[k].allnum;
upson(l,r,k);
int mid=(l+r)/2;
if(id<=mid)
return query(l,mid,k<<1,id);
else return query(mid+1,r,(k<<1)|1,id);
}
void swp(int &a,int &b)
{
int tt=a; a=b; b=tt;
}
void Operat(int u,int v,int c)
{
int fu=top[u], fv=top[v];
while(fu!=fv)
{
if(deep[fu]<deep[fv])
{
swp(fu,fv); swp(u,v);
}
update(1,pos,1,p[fu],p[u],c);
u=fath[fu]; fu=top[u];
}
if(deep[u]>deep[v])
swp(u,v);
update(1,pos,1,p[u],p[v],c);//点权更新与边权更新的区别之一:点p[u],边p[son[u]]
}
int main()
{
int n,m,q,val[N];
while(scanf("%d%d%d",&n,&m,&q)>0)
{
init(n);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
mapt[u].push_back(v);
mapt[v].push_back(u);
}
dfs(1,1,1);
getpos(1,1);
for(int i=1;i<=n;i++)
a[p[i]]=val[i]; //一定要注意转换成在线段树上的对应位置
pos=n;
build(1,pos,1);
while(q--)
{
int u,v,c;
char ch[10];
scanf("%s%d",ch,&u);
if(ch[0]=='Q')
printf("%d\n",query(1,pos,1,p[u]));
else
{
scanf("%d%d",&v,&c);
if(ch[0]=='D') c=-c;
Operat(u,v,c);
}
}
}
return 0;
}
HDU 3966Aragorn's Story(树链剖分)点权更新模板
标签:树链剖分
原文地址:http://blog.csdn.net/u010372095/article/details/45534491