Description
题目背景:
尊者神高达作为一个萌新,在升级路上死亡无数次后被一只大黄叽带回了师门。他加入师门后发现有无穷无尽的师兄弟姐妹,这几天新副本开了,尊者神高达的师门作为一个 pve师门,于是他们决定组织一起去开荒。
题目描述:
师门可以看做以 1 为根的一棵树,师门中的每一个人都有一定的装备分数。一共会有 q 个事件。每个事件可能是一次开荒,也可能是因为开荒出了好装备而导致一个人的装分出现了变化。对于一次开荒,会有 k 个人组织,由于师门的号召力很强,所以所有在组织者中任意两个人简单路径上的人都会参加。
尊者神高达作为一个萌新,在升级路上死亡无数次后被一只大黄叽带回了师门。他加入师门后发现有无穷无尽的师兄弟姐妹,这几天新副本开了,尊者神高达的师门作为一个 pve师门,于是他们决定组织一起去开荒。
题目描述:
师门可以看做以 1 为根的一棵树,师门中的每一个人都有一定的装备分数。一共会有 q 个事件。每个事件可能是一次开荒,也可能是因为开荒出了好装备而导致一个人的装分出现了变化。对于一次开荒,会有 k 个人组织,由于师门的号召力很强,所以所有在组织者中任意两个人简单路径上的人都会参加。
Input
第一行 n ,q;
接下来 1 行 n 个数,代表每个人的分值;
接下来 n-1 行 u,v 代表一条边
接下来 q 行
Q 代表询问,接下来 k 个数代表组织的人数,读入为 0时停止读入。
C 代表修改,输入 x,w 代表将 x 的分值变为 w
接下来 1 行 n 个数,代表每个人的分值;
接下来 n-1 行 u,v 代表一条边
接下来 q 行
Q 代表询问,接下来 k 个数代表组织的人数,读入为 0时停止读入。
C 代表修改,输入 x,w 代表将 x 的分值变为 w
Output
共 Q 的数量行,为开荒的人的总分值
Sample Input
4 4 10 5 2 2 1 2 2 3 2 4 Q 3 4 0 C 3 200 Q 3 4 0 Q 1 4 0
Sample Output
9 207 17 样例解释: 第一次询问,参加的人有 2,3,4 5+2+2=9 第一次修改,权值为 10 5 200 2 第二次询问,参加的人有 2,3,4 5+200+2=207 第三次询问,参加的人有 1,2,4 10+5+2=17
Data Constraint
数据范围:
20%的数据 n<=10000,q<=500;
另外 20%的数据 k=2
另外 20%的数据 没有修改操作
所有数据 n,q<=100000,所有询问 k 的和<=1000000
保证数据合法
20%的数据 n<=10000,q<=500;
另外 20%的数据 k=2
另外 20%的数据 没有修改操作
所有数据 n,q<=100000,所有询问 k 的和<=1000000
保证数据合法
分析
由于询问点少,我们考虑建虚树(假
然后用树状数组维护关键节点的和就行了


#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #define lowbit(x) x&-x using namespace std; typedef long long ll; const int N=1e5+10; struct Edge { int u,v,nx; }g[2*N]; int cnt,list[N]; ll c[N],w[N]; int st[N],ed[N],tme; int dep[N],f[N][21]; int a[2*N],acnt; int n,q; void Addedge(int u,int v) { g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt; } int LCA(int u,int v) { if (dep[u]<dep[v]) swap(u,v); for (int i=20;i>=0;i--) if (dep[f[u][i]]>=dep[v]) u=f[u][i]; if (u==v) return u; for (int i=20;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return f[u][0]; } void Dfs(int u,int fa) { st[u]=++tme;dep[u]=dep[fa]+1; for (int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) { f[g[i].v][0]=u; Dfs(g[i].v,u); } ed[u]=tme; } void Add(int x,ll y) { for (int i=x;i<=n;i+=lowbit(i)) c[i]+=y; } ll Get_Sum(int x) { ll ans=0; for (int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans; } bool Cmp(int a,int b) { return st[a]<st[b]; } int main() { freopen("kaihuang.in","r",stdin); freopen("kaihuang.out","w",stdout); scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) scanf("%lld",&w[i]); for (int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); Addedge(u,v);Addedge(v,u); } Dfs(1,0); for (int i=1;i<=n;i++) Add(st[i],w[i]),Add(ed[i]+1,-w[i]); for (int i=1;i<=q;i++) { char c; do { scanf("%c",&c); } while (c!='C'&&c!='Q'); if (c=='C') { int a;ll b; scanf("%d%lld",&a,&b); Add(st[a],b-w[a]);Add(ed[a]+1,w[a]-b); w[a]=b; continue; } acnt=0; do { acnt++; scanf("%d",&a[acnt]); } while (a[acnt]!=0); acnt--; sort(a+1,a+acnt+1,Cmp); int fakeacnt=acnt; for (int i=1;i<fakeacnt;i++) a[++acnt]=LCA(a[i],a[i+1]); sort(a+1,a+acnt+1,Cmp);acnt=unique(a+1,a+acnt+1)-a-1; stack<int> stk; ll ans=0; while (!stk.empty()) stk.pop(); for (int i=1;i<=acnt;i++) { for (;!stk.empty()&&ed[stk.top()]<st[a[i]];stk.pop()); ans+=!stk.empty()?Get_Sum(st[a[i]])-Get_Sum(st[stk.top()]):w[a[i]]; stk.push(a[i]); } printf("%lld\n",ans); } }