Description
题目背景:
尊者神高达作为一个萌新,在升级路上死亡无数次后被一只大黄叽带回了师门。他加入师门后发现有无穷无尽的师兄弟姐妹,这几天新副本开了,尊者神高达的师门作为一个 pve师门,于是他们决定组织一起去开荒。
题目描述:
师门可以看做以 1 为根的一棵树,师门中的每一个人都有一定的装备分数。一共会有 q 个事件。每个事件可能是一次开荒,也可能是因为开荒出了好装备而导致一个人的装分出现了变化。对于一次开荒,会有 k 个人组织,由于师门的号召力很强,所以所有在组织者中任意两个人简单路径上的人都会参加。
题解
可以想到是用虚树来实现,
那么现在问题就转化成了求树上某些链的权值和,
而且还有支持单点修改。
这就是链剖了。
其实虚树也不一定要真正地建出来,
只是用类似的方法求出那一棵树。
code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define N 200003
#define P putchar
#define G getchar
#define ls (x<<1)
#define rs (x<<1|1)
#define LL long long
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int abs(int x){return x<0?-x:x;}
int sqr(int x){return x*x;}
void write(LL x){if(x>9) write(x/10);P(x%10+'0');}
LL l[N*4],r[N*4],V[N*4],ops,ans,sum;
int nxt[N],to[N],lst[N],v[N],vv[N],tot;
int si[N],top[N],son[N],fa[N],id[N],now,rank[N];
int dep[N],f[17][N];
int n,m,t,opl,opr,opx,x,y,q,a[N];
int z[N*2],tp;
void ins(int x,int y)
{
nxt[++tot]=lst[x];
to[tot]=y;
lst[x]=tot;
}
void dfs(int x)
{
rank[x]=++now;dep[x]=dep[fa[x]]+1;f[0][x]=fa[x];
int t=0;si[x]=1;
for(int i=lst[x];i;i=nxt[i])
if(to[i]!=fa[x])
{
fa[to[i]]=x;
dfs(to[i]);
si[x]+=si[to[i]];
if(si[to[i]]>t)t=si[to[i]],son[x]=to[i];
}
}
void dfs_(int x,int t)
{
vv[id[x]=++now]=v[x];
top[x]=t;
if(son[x])dfs_(son[x],t);
for(int i=lst[x];i;i=nxt[i])
if(to[i]!=fa[x] && to[i]!=son[x])
dfs_(to[i],to[i]);
}
void build(int x,int ll,int rr)
{
l[x]=ll;r[x]=rr;
if(ll==rr)
{
V[x]=vv[ll];
return;
}
int m=(ll+rr)>>1;
build(ls,ll,m);
build(rs,m+1,rr);
V[x]=V[ls]+V[rs];
}
void work(int x)
{
if(opl<=l[x] && r[x]<=opr)
{
if(opx==1)V[x]=ops;else
if(opx==2)ops=ops+V[x];
return;
}
int m=(l[x]+r[x])>>1;
if(opl<=m)work(ls);
if(m<opr)work(rs);
V[x]=V[ls]+V[rs];
}
void find(int x,int y)
{
for(;dep[y]<dep[top[x]];x=fa[top[x]])
opl=id[top[x]],opr=id[x],work(1);
opl=id[y];opr=id[x];work(1);
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int j=16;j+1;j--)
if(dep[f[j][x]]>=dep[y])x=f[j][x];
if(x==y)return x;
for(int j=16;j+1;j--)
if(f[j][x]^f[j][y])x=f[j][x],y=f[j][y];
return f[0][x];
}
bool cmp(int x,int y){return rank[x]<rank[y];}
int main()
{
freopen("kaihuang.in","r",stdin);
freopen("kaihuang.out","w",stdout);
read(n);read(m);
for(int i=1;i<=n;i++)read(v[i]);
for(int i=1;i<n;i++)read(x),read(y),ins(x,y),ins(y,x);
now=0,dfs(1);
now=0,dfs_(1,1);
build(1,1,n);
for(int j=1;j<17;j++)
for(int i=1;i<=n;i++)
f[j][i]=f[j-1][f[j-1][i]];
for(int i=1;i<=m;i++)
{
for(;ch!='Q' && ch!='C';ch=G());
if(ch=='Q')
{
for(a[q=0]=-1;a[q];)read(a[++q]);q--;
sort(a+1,a+1+q,cmp);ops=v[a[1]];opx=2;
z[tp=1]=a[1];
for(int i=2;i<=q;i++)
{
x=lca(a[i],z[tp]),find(a[i],x),ops=ops-v[x];
for(;tp && dep[z[tp]]>dep[x];tp--);
if(tp==0)find(z[1],x),ops=ops-v[z[1]];
z[++tp]=x;z[++tp]=a[i];
}
write(ops);P('\n');
}
else
{
read(x);read(y);opx=1;
opl=opr=id[x];ops=y;work(1);
v[x]=y;
}
}
return 0;
}