做之前了解树链剖分的相关内容。
题意:给出一棵树,每个节点有一些敌人,有三种操作,I:x,y,路径上的所有点的人数+w。D:x,y,路径上的所有点的人数-w。Q:节点x的人数。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
const int N=100005;
int son[N];//重儿子;
int sz[N];//以该节点为根的子结点数(包括自己)
int dep[N];//该节点到根的距离
int top[N];//该节点所在重链最顶端节点
int father[N];//每个节点的父节点
int head[N];//用于构造邻接表
int ti[N];//该点映射到线段树中的位置
int num,idx,a[N];
struct edge
{
int st;
int next;
}e[N];
void addedge(int x,int y)//构造邻接表存储边
{
e[num].st=x;e[num].next=head[y];head[y]=num++;
e[num].st=y;e[num].next=head[x];head[x]=num++;
}
//****************树链剖分****************
void find_son(int u)//第一次dfs求出father·dep·size·son数组
{
int i,v;
sz[u]=1;son[u]=0;
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].st;
if(v==father[u]) continue;
father[v]=u;dep[v]=dep[u]+1;
find_son(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void find_ti(int u,int fa)//第二次dfs求top和ti数组
{
int i,v;
ti[u]=idx++;
top[u]=fa;
if(son[u]!=0) find_ti(son[u],top[u]);
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].st;
if(v==son[u]||v==father[u]) continue;
find_ti(v,v);
}
}
//***************线段树****************
struct Tree
{
int r,l;
int ct;//该区间的增量
}T[N];
void buildtree(int l,int r,int id)//建线段树
{
T[id].l=l;
T[id].r=r;
T[id].ct=0;
if(l==r) return ;
int mid=(l+r)>>1;
int li=id<<1;
int ri=li+1;
buildtree(l,mid,li);
buildtree(mid+1,r,ri);
}
void Insert(int l,int r,int id,int w)//为线段树保存的l~r区间增加w
{
if(T[id].l==l&&T[id].r==r)
{
T[id].ct+=w;
return;
}
int mid=(T[id].l+T[id].r)>>1;
int li=id<<1;
int ri=li+1;
if(mid>=r) Insert(l,r,li,w);
else if(mid<l) Insert(l,r,ri,w);
else {
Insert(l,mid,li,w);
Insert(mid+1,r,ri,w);
}
}
int findw(int i,int id,int w) //线段树区间的查询操作
{
if(T[id].l==T[id].r)
return w+T[id].ct;
int mid=(T[id].l+T[id].r)>>1,li=id<<1,ri=li+1;
if(mid>=i)return findw(i,li,w+T[id].ct);
else return findw(i,ri,w+T[id].ct);
}
void lca(int x,int y,int w)//为原题要求x~y路径上各点增加w
{
while(top[x]!=top[y])//不在同一条重边上,不断更新当前所在重边
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
Insert(ti[top[x]],ti[x],1,w);
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);//最终在同一条重边
Insert(ti[x],ti[y],1,w);
}
int main()
{
int i,n,m,q,x,y,w;
char str[10];
while(scanf("%d%d%d",&n,&m,&q)!=EOF)
{
memset(head,-1,sizeof(head));
num=0;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
father[1]=sz[0]=0;dep[1]=idx=1;
find_son(1);
find_ti(1,1);
buildtree(1,n,1);
while(q--)
{
scanf("%s",str);
if(str[0]=='Q')
{
scanf("%d",&x);
printf("%d\n",a[x]+findw(ti[x],1,0));
}
else
{
scanf("%d%d%d",&x,&y,&w);
if(str[0]=='I') w=-w;
lca(x,y,-w);
}
}
}
return 0;
}