题目描述
Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, the enemy has N camps out of his kingdom and M edges connect them. It is guaranteed that for any two camps, there is one and only one path connect them. At first Aragorn know the number of enemies in every camp.
But the enemy is cunning , they will increase or decrease the number of soldiers in camps. Every time the enemy change the number of soldiers, they will set two camps C1 and C2. Then, for C1, C2 and all camps on the path from C1 to C2, they will increase or decrease K soldiers to these camps. Now Aragorn wants to know the number of soldiers in some particular camps real-time.
题目大意
三种操作:
- 点\(x\)到点\(y\)的路径上的每一个点的权值都+\(v\)
- 点\(x\)到点\(y\)的路径上的每一个点的权值都-\(v\)
- 查询点\(u\)的权值
解法
树链剖分的模板题,拿过来随便练练手。
我会在第4将的xio讲堂上详细讲解树剖,这里就稍微介绍一下。
树剖在沃的理解上,就是将一棵树通过dfs序或者其他的顺序,和轻重关系来展开到一个一位数组中,然后我们将各个在树上的操作变成一位的操作,这种操作就只需要用数据结构来维护就可以了。
那么反观这道题,我们就将树展开到一维上,并且用线段树来维护,其实非常好理解。
ac代码
#include<bits/stdc++.h>
#define ms(a,b) memset(a,b,sizeof(a))
#define N 50005
#define M 50005
using namespace std;
struct edge{
int to,nt;
}E[M<<1];
int H[N],a[N],val[N],sz[N],dep[N],son[N],top[N],idx[N],fa[N];
int cnt,tot,n,m,p;
int read(){
int w=0,x=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
void addedge(int u,int v){
E[++cnt]=(edge){v,H[u]}; H[u]=cnt;
}
struct segment_tree{//线段树的各个操作,比较简单不多做讲解
#define lson (nod<<1)
#define rson (nod<<1|1)
#define mid (l+r>>1)
int tr[N<<2],add[N<<2];
void init(){
ms(tr,0);ms(add,0);
}
void pushup(int nod){
tr[nod]=tr[lson]+tr[rson];
}
void pushdown(int l,int r,int nod){
if(!add[nod]) return;
tr[lson]+=add[nod]*(mid-l+1);
tr[rson]+=add[nod]*(r-mid);
add[lson]+=add[nod];
add[rson]+=add[nod];
add[nod]=0;
}
void build(int l,int r,int nod,int *a){
if(l>=r){
tr[nod]=a[l];
return;
}
build(l,mid,lson,a);
build(mid+1,r,rson,a);
pushup(nod);
}
void update(int l,int r,int ql,int qr,int v,int nod){
if(ql<=l&&r<=qr){
tr[nod]+=v*(r-l+1);
add[nod]+=v;
return;
}
pushdown(l,r,nod);
if(ql<=mid) update(l,mid,ql,qr,v,lson);
if(qr>mid) update(mid+1,r,ql,qr,v,rson);
pushup(nod);
}
int query(int l,int r,int k,int nod){
if(l==r) return tr[nod];
pushdown(l,r,nod);
if(k<=mid) return query(l,mid,k,lson);
else return query(mid+1,r,k,rson);
}
}T;
void dfs1(int u,int ft,int dp){//第一遍dfs,求出sz,fa,dep。
sz[u]=1;
fa[u]=ft;
dep[u]=dp;
int maxson=-1;
for(int e=H[u];e;e=E[e].nt){
int v=E[e].to;
if(v==fa[u]) continue;
dfs1(v,u,dp+1);
sz[u]+=sz[v];
if(sz[v]>maxson) maxson=sz[v],son[u]=v;
}
}
void dfs2(int u,int tp){//第二遍dfs,求出idx,val,top,和将各个重点连成重边
idx[u]=++tot;
val[tot]=a[u];
top[u]=tp;
if(!son[u]) return;
dfs2(son[u],tp);
for(int e=H[u];e;e=E[e].nt){
int v=E[e].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void init(){
cnt=0,tot=0;
ms(son,0);ms(E,0);ms(H,0);ms(top,0);ms(sz,0);ms(idx,0);ms(val,0);
}
int point_query(int u){return T.query(1,n,idx[u],1);}
void chain_update(int u,int v,int w){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
T.update(1,n,idx[top[u]],idx[u],w,1);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
T.update(1,n,idx[u],idx[v],w,1);
}
int main(){
while(~scanf("%d%d%d",&n,&m,&p)){
T.init(); init();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++) {
int u=read(),v=read();
addedge(u,v);
addedge(v,u);
}
dfs1(1,-1,1);
dfs2(1,1);
T.build(1,n,1,val);
while(p--){
char opt[5];
scanf("%s",opt);
if(opt[0]=='Q'){
int x=read();
printf("%d\n",point_query(x));
}
if(opt[0]=='I'){
int x=read(),y=read(),z=read();
chain_update(x,y,z);
}
if(opt[0]=='D'){
int x=read(),y=read(),z=read();
chain_update(x,y,-z);
}
}
}
return 0;
}