Query on a graph
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 325 Accepted Submission(s): 73
We will ask you to perform some instructions of the following forms.
MODIFY u k d: weight of all nodes in S(u,k) increase by d or decrease by -d.
QUERY u k: ask for the sum of weight of all nodes in S(u,k).
In the beginning, the weight of all nodes are 0.
2 6 1 2 2 3 3 4 4 1 4 5 3 6 5 MODIFY 1 1 3 MODIFY 3 1 2 MODIFY 5 2 1 QUERY 3 2 QUERY 4 1 6 1 2 2 3 3 1 1 4 2 5 3 6 5 MODIFY 3 1 5 MODIFY 2 2 2 QUERY 6 1 MODIFY 4 1 -2 QUERY 2 2
21 14 14 28
题意:一个图有n个点,n条边(一定存在环,但没有自环和重边)
定义D(u,v)为u到v的距离,S(u,k)为所有D(u,v)<=k的节点v的集合
有m次询问(0<=k<=2):
①u k d:将集合S(u,k)的所有节点的权值加d
②u k:询问集合S(u,k)的所有节点的权值之和
题解:线段树
首先将图分为2个部分:1个环和若干棵树(每棵树的根节点在环上)
这一步可以通过拓扑排序完成
设val[u]为节点u的权值,fa[u]为父亲,son[u]为儿子,sson[u]孙子
根据k的取值分情况讨论:
①k = 0时
ans = val[u]
②k = 1时
1)u为树上节点:ans = ∑val[son[u]] + val[u] + val[fa[u]]
2)u为环上节点:ans = ∑val[son[u]] + val[u] + val[u在环上的邻居]
③k = 2时
设father = fa[u]
1)u为树上节点:ans = ∑val[son[u]] + ∑val[sson[u]] + val[father] + ∑val[son[father]]
(1)father为树上节点:ans += val[fa[father]]
(2)father为环上节点:ans += ∑val[father在环上的邻居]
2)u为环上节点:ans = ∑val[son[u]] + ∑val[sson[u]] + val[u在环上的邻居] + val[邻居的邻居] + ∑val[son[邻居]]
知道ans该怎么求解了,重点是怎么求和。逐个求和的话复杂度高达O(n^2)显然是不行的,因此需要
用线段树进行区间维护。我们可以知道,对一个棵树求BFS序后,深度相同的节点的序号是相邻的。
对于节点u,如果知道它儿子的最小BFS序号L和最大BFS序号R,那么它儿子的所有序号就在[L,R]中。
因此我们就有了维护权值的方法:类似于树链剖分,我们将所有节点都用BFS序编号并存入线段树,
如果要访问某个节点u的所有儿子,只要知道其序号区间[L,R],这个区间序号可以用sonL[u]和sonR[u]
维护,类似的u孙子的区间序号也可以用ssonL[u]和ssonR[u]存放
至此问题就解决了,由于用到线段树,总复杂度为O(mlogn)
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Edge{
int v,nxt;
}E[MX*2];
int head[MX],IN[MX],tot,n;
void init_edge(){
for(int i=1;i<=n;i++) {IN[i]=0;head[i]=-1;}
tot=0;
}
void add_edge(int u,int v){
E[tot].v=v;
E[tot].nxt=head[u];
head[u]=tot++;
IN[v]++;
}
void top_sort(){
queue<int>q;
for(int i=1;i<=n;i++) if(IN[i]==1) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(IN[v]>1){
IN[v]--;
if(IN[v]==1) q.push(v);
}
}
}
}
int p[MX],fp[MX],fa[MX],sz;
int sonL[MX],sonR[MX],ssonL[MX],ssonR[MX];
void bfs(int top){
queue<int>q;
q.push(top);
while(!q.empty()){
int u=q.front();q.pop();
sonL[u]=ssonL[u]=INF;
sonR[u]=ssonR[u]=0;
//printf("[%d %d]\n",u,p[u]);
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(IN[v]>1||v==fa[u]) continue;
p[v]=++sz;
fp[sz]=v;
fa[v]=u;
sonL[u]=min(sonL[u],p[v]);
sonR[u]=max(sonR[u],p[v]);
q.push(v);
}
ssonL[fa[u]]=min(ssonL[fa[u]],sonL[u]);
ssonR[fa[u]]=max(ssonR[fa[u]],sonR[u]);
}
}
LL sum[MX<<2],add[MX<<2];
void build(int l,int r,int rt){
sum[rt]=add[rt]=0;
if(l==r) return;
int m=(l+r)>>1;
build(lson);
build(rson);
}
void PushDown(int m,int rt){
if(add[rt]){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
sum[rt<<1]+=add[rt]*(m-(m>>1));
sum[rt<<1|1]+=add[rt]*(m>>1);
add[rt]=0;
}
}
void PushUP(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int L,int R,int c,int l,int r,int rt){
if(L==0||R==0) return;
if(L<=l&&R>=r){
sum[rt]+=(LL)(r-l+1)*c;
add[rt]+=c;
return;
}
PushDown(r-l+1,rt);
int m=(l+r)>>1;
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
PushUP(rt);
}
LL query(int L,int R,int l,int r,int rt){
if(L==0||R==0) return 0;
if(L<=l&&R>=r) return sum[rt];
PushDown(r-l+1,rt);
int m=(l+r)>>1;
LL ret=0;
if(L<=m) ret+=query(L,R,lson);
if(R>m) ret+=query(L,R,rson);
PushUP(rt);
return ret;
}
int ver[MX][2];
void init(){
for(int i=1;i<=n;i++) fa[i]=0;
sz=0;
}
void pre_solve(){
init();
top_sort();
for(int u=1;u<=n;u++) if(IN[u]>1){
int j=0;
for(int i=head[u];~i;i=E[i].nxt){
int v=E[i].v;
if(IN[v]>1) ver[u][j++]=v;
}
p[u]=++sz;
fp[sz]=u;
bfs(u);
}
build(1,n,1);
}
void solve_modify(int u,int k,int d){
int father=fa[u];
if(k==0) update(p[u],p[u],d,1,n,1);
else if(k==1){
update(sonL[u],sonR[u],d,1,n,1);
update(p[u],p[u],d,1,n,1);
if(IN[u]==1) update(p[father],p[father],d,1,n,1);
else{
for(int i=0;i<2;i++){
int v=ver[u][i];
update(p[v],p[v],d,1,n,1);
}
}
}
else{
update(sonL[u],sonR[u],d,1,n,1);
update(ssonL[u],ssonR[u],d,1,n,1);
if(IN[u]==1){
update(p[father],p[father],d,1,n,1);
update(sonL[father],sonR[father],d,1,n,1);
if(IN[father]==1) update(p[fa[father]],p[fa[father]],d,1,n,1);
else{
for(int i=0;i<2;i++){
int v=ver[father][i];
update(p[v],p[v],d,1,n,1);
}
}
}
else{
update(p[u],p[u],d,1,n,1);
int vv[2],cnt=0;
for(int i=0;i<2;i++){
int v=ver[u][i];
update(p[v],p[v],d,1,n,1);
update(sonL[v],sonR[v],d,1,n,1);
for(int j=0;j<2;j++){
if(ver[v][j]==u||ver[v][j]==ver[u][0]||ver[v][j]==ver[u][1]) continue;
if(cnt>0&&ver[v][j]==vv[cnt-1]) continue;
vv[cnt++]=ver[v][j];
}
}
for(int i=0;i<cnt;i++){
update(p[vv[i]],p[vv[i]],d,1,n,1);
}
}
}
}
LL solve_query(int u,int k){
int father=fa[u];
LL ret=0;
if(k==0) ret+=query(p[u],p[u],1,n,1);
else if(k==1){
ret+=query(sonL[u],sonR[u],1,n,1);
ret+=query(p[u],p[u],1,n,1);
if(IN[u]==1) ret+=query(p[father],p[father],1,n,1);
else{
for(int i=0;i<2;i++){
int v=ver[u][i];
ret+=query(p[v],p[v],1,n,1);
}
}
}
else{
ret+=query(sonL[u],sonR[u],1,n,1);
ret+=query(ssonL[u],ssonR[u],1,n,1);
if(IN[u]==1){
ret+=query(p[father],p[father],1,n,1);
ret+=query(sonL[father],sonR[father],1,n,1);
if(IN[father]==1) ret+=query(p[fa[father]],p[fa[father]],1,n,1);
else{
for(int i=0;i<2;i++){
int v=ver[father][i];
ret+=query(p[v],p[v],1,n,1);
}
}
}
else{
ret+=query(p[u],p[u],1,n,1);
int vv[2],cnt=0;
for(int i=0;i<2;i++){
int v=ver[u][i];
ret+=query(p[v],p[v],1,n,1);
ret+=query(sonL[v],sonR[v],1,n,1);
for(int j=0;j<2;j++){
if(ver[v][j]==u||ver[v][j]==ver[u][0]||ver[v][j]==ver[u][1]) continue;
if(cnt>0&&ver[v][j]==vv[cnt-1]) continue;
vv[cnt++]=ver[v][j];
}
}
for(int i=0;i<cnt;i++){
ret+=query(p[vv[i]],p[vv[i]],1,n,1);
}
}
}
return ret;
}
int main(){
//freopen("in.txt","r",stdin);
int T,m,u,v,k,d;
char op[10];
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init_edge();
for(int i=1;i<=n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);add_edge(v,u);
}
pre_solve();
scanf("%d",&m);
while(m--){
scanf("%s",op);
if(op[0]=='M'){
scanf("%d%d%d",&u,&k,&d);
solve_modify(u,k,d);
}
else {
scanf("%d%d",&u,&k);
printf("%lld\n",solve_query(u,k));
}
}
}
return 0;
}