Query on a graph
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 369 Accepted Submission(s): 81
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
----------------------------------------------------------------------------------------
题解:看到修改和查询的题目就往数据结构上去想。
而到某个点的距离 <= k的一些数全部+或-某个值,我们想到按照bfs序将树展开,展开之后这些数就对应到了链上的某一段连续的序列了,就可以利用线段树的区间修改来维护这段bfs序了。
这里有个麻烦的地方是,给出来的图是一个基环外向树,因此,我们先用tarjan算法讲环找出来(当然也可以用其他更为简单的算法找环),然后把环去掉,形成森林,对森林中的每一棵树都做一遍bfs序,然后再跑一边dfs序,得到从每个点u出发,走一步的儿子对应区间左右端点。走两步的孙子对应的区间左右端点。这样的话,就可以将这棵树映射到一颗线段树上了(注意线段树要动态开点,不然会MLE)。
下面就要开始实现修改和查询的功能了。
这两种功能实现起来类似(代码复制粘贴以后稍微改一改就好了)。
这里就直说区间修改。
为了方便起见,我们还需要对基环上的点进行一次dfs操作,以便将基环展开为一条链,存到数组上。
这有很多种情况:
1.k = 0的时候,如果u在基环上且不在树上直接在链上对应的位置+addval
如果u在某颗树上的话,要在这棵树对应的线段树里+addval
2.k = 1的时候,如果u在基环上的话,pre 找到基环上左边的点,该点执行k=0时候的操作,post找到基环上右边的点,该点也执行k = 0的操作
然后u本身也要执行k = 0的操作,然后如果u还在树上的话,对u儿子对应的区间进行+addval操作。
3.k = 2的时候,很麻烦。。。。仔细考虑一下吧(例如要对u的孙子节点+addval,对u的儿子节点+addval,对u的父亲节点的儿子节点+addval等等等等,情况很多,具体请参照我的代码看)
500多行的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
int cas = 0;
struct segtree{
LL *val;
LL *addmark;
int n;
void init(int N){
n = N;
val = new LL[(n<<2)+10];
addmark = new LL[(n<<2)+10];
memset(val,0,sizeof(LL) * ((n<<2) + 10));
memset(addmark,0,sizeof(LL) * ((n<<2) + 10));
}
void pushdown(int root,int L,int R){
if(addmark[root]){
int mid = (L + R) / 2;
addmark[root*2] += addmark[root] ;
addmark[root*2+1] += addmark[root] ;
val[root*2] += addmark[root] * (mid - L + 1);
val[root*2+1] += addmark[root] * (R - mid);
addmark[root] = 0;
}
}
void pushup(int root){
val[root] = val[root * 2] + val[root * 2 + 1];
}
LL query(int root,int begin,int end,int left,int right)
{
int p1,p2;
if(left > end||right < begin)
return 0;
if(begin>=left&&end<=right)
return val[root];
pushdown(root,begin,end);
LL a = query(root*2,begin,(begin+end)/2,left,right);
LL b = query(root*2+1,(begin+end)/2+1,end,left,right);
return a + b;
}
void update(int root,int begin,int end,int ubegin,int uend,LL addval)
{
if(ubegin > end || uend < begin)
return ;
if(begin >= ubegin && end <= uend){
addmark[root] += addval;
val[root] += addval * (end - begin + 1);
return ;
}
pushdown(root,begin,end);
int m = (begin+end)/2;
update(root*2,begin,m,ubegin,uend,addval);
update(root*2+1,m+1,end,ubegin,uend,addval);
pushup(root);
}
}segs[MAXN];
int head[MAXN];
int cnt;
struct edge{
int v;
int next;
int cost;
}Es[MAXN<<1];
void init(){
cnt = 0;
memset(head,-1,sizeof(head));
}
inline void add_edge(int i,int j,int cost){
Es[cnt].v = j;
Es[cnt].cost = cost;
Es[cnt].next = head[i];
head[i] = cnt++;
}
int n;
int DFN[MAXN],LOW[MAXN];
int stk[MAXN],vis[MAXN],belong[MAXN];
int idx,sccnum,tot;
vector<int> scc[MAXN];
void tarjan(int x,int fa){
DFN[x] = LOW[x] = ++ tot;
stk[++idx] = x;
vis[x] = 1;
for(int e = head[x];e != -1;e = Es[e].next){
int v = Es[e].v;
if(v == fa) continue;
if(!DFN[v]){
tarjan(v,x);
LOW[x] = min(LOW[x],LOW[v]);
}
else if(vis[v]){
LOW[x] = min(LOW[x],DFN[v]);
}
}
if(DFN[x] == LOW[x]){
++sccnum;
int item;
do{
item = stk[idx--];
belong[item] = sccnum;
scc[sccnum].push_back(item);
vis[item] = 0;
}while(x != item);
}
}
int pa[MAXN],dep[MAXN],bfs_order[MAXN][3][2],pos[MAXN],siz[MAXN],loop_link[MAXN];
int belong_tree[MAXN];
LL loop_val[MAXN];
int loop_pos[MAXN];
int loop,link_cnt;
vector<int> orders[MAXN];
void bfs(int x){
map<int,int> vismp;
vismp.clear();
queue<int> Q;
vismp[x] = 1;
dep[x] = 0;
Q.push(x);
pos[x] = 0;
orders[x].push_back(x);
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int e = head[u];e != -1;e = Es[e].next){
int v = Es[e].v;
if(vismp[v] || belong[v] == loop) continue;
vismp[v] = 1;
dep[v] = dep[u] + 1;
pa[v] = u;
pos[v] = orders[x].size();
orders[x].push_back(v);
Q.push(v);
}
}
}
void deal(int rt){
if(!belong_tree[rt]) belong_tree[rt] = rt;
siz[rt] = 1;
bfs_order[rt][0][0] = bfs_order[rt][0][1] = pos[rt];
int x1 = -1,y1 = -1;
int x2 = -1,y2 = -1;
for(int e = head[rt];e != -1;e = Es[e].next){
int v = Es[e].v;
if(v == pa[rt] || belong[v] == loop) continue;
belong_tree[v] = belong_tree[rt];
deal(v);
siz[rt] += siz[v];
if(x1 == -1 && y1 == -1){
x1 = y1 = pos[v];
}
else if(bfs_order[v][0][0] != -1 && bfs_order[v][0][1] != -1){
x1 = min(x1,bfs_order[v][0][0]);
y1 = max(y1,bfs_order[v][0][1]);
}
if(x2 == -1 && y2 == -1){
x2 = bfs_order[v][1][0];
y2 = bfs_order[v][1][1];
}
else if (bfs_order[v][1][0] != -1 && bfs_order[v][1][1] != -1){
x2 = min(x2,bfs_order[v][1][0]);
y2 = max(y2,bfs_order[v][1][1]);
}
}
bfs_order[rt][1][0] = x1,bfs_order[rt][1][1] = y1;
bfs_order[rt][2][0] = x2,bfs_order[rt][2][1] = y2;
}
LL ask_zero(int u){
int p = belong_tree[u];
if(p){
int l = bfs_order[u][0][0]+1;
int r = bfs_order[u][0][1]+1;
return segs[p].query(1,1,segs[p].n,l,r);
}
else{
return loop_val[loop_pos[u]];
}
}
LL ask_tree_one(int u){
int p = belong_tree[u];
if(p){
int l = bfs_order[u][1][0]+1;
int r = bfs_order[u][1][1]+1;
if(l && r)
return segs[p].query(1,1,segs[p].n,l,r);
}
return 0;
}
LL ask_tree_two(int u){
int p = belong_tree[u];
if(p){
int l = bfs_order[u][2][0]+1;
int r = bfs_order[u][2][1]+1;
if(l && r )
return segs[p].query(1,1,segs[p].n,l,r);
}
return 0;
}
void md_zero(int u,int d){
int p = belong_tree[u];
if(p){
int l = bfs_order[u][0][0]+1;
int r = bfs_order[u][0][1]+1;
segs[p].update(1,1,segs[p].n,l,r,d);
}
else{
loop_val[loop_pos[u]] += d;
}
}
void md_tree_one(int u,int d){
int p = belong_tree[u];
if(!p) return ;
int l = bfs_order[u][1][0]+1;
int r = bfs_order[u][1][1]+1;
if(l && r)
segs[p].update(1,1,segs[p].n,l,r,d);
}
void md_tree_two(int u,int d){
int p = belong_tree[u];
if(!p) return ;
int l = bfs_order[u][2][0]+1;
int r = bfs_order[u][2][1]+1;
if(l && r)
segs[p].update(1,1,segs[p].n,l,r,d);
}
LL ask(int u,int k){
if(k == 0){
return ask_zero(u);
}
else if(k == 1){
if(pa[u] == 0) // in the loop
{
LL ans = 0;
int pre = (loop_pos[u] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[u] + link_cnt + 1) % link_cnt;
post = loop_link[post];
ans += ask_zero(u);
ans += ask_tree_one(u);
ans += ask_zero(pre);
ans += ask_zero(post);
return ans;
}
else{
LL ans = 0;
ans += ask_zero(pa[u]);
ans += ask_zero(u);
ans += ask_tree_one(u);
return ans;
}
}
else if(k == 2){
if(pa[u] == 0){
LL ans = 0;
map<int,int> vismp[3];
vismp[0].clear(),vismp[1].clear(),vismp[2].clear();
int pre_pre = (loop_pos[u] + link_cnt - 2) % link_cnt;
pre_pre = loop_link[pre_pre];
int pre = (loop_pos[u] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[u] + link_cnt + 1) % link_cnt;
post = loop_link[post];
int post_post = (loop_pos[u] + link_cnt + 2) % link_cnt;
post_post = loop_link[post_post];
if(!vismp[0][pre_pre]){
vismp[0][pre_pre] = 1;
ans += ask_zero(pre_pre);
}
if(!vismp[0][pre]){
vismp[0][pre] = 1;
ans += ask_zero(pre);
}
if(!vismp[1][pre]){
vismp[1][pre] = 1;
ans += ask_tree_one(pre);
}
if(!vismp[0][u]){
vismp[0][u] = 1;
ans += ask_zero(u);
}
if(!vismp[1][u]){
vismp[1][u] = 1;
ans += ask_tree_one(u);
}
if(!vismp[2][u]){
vismp[2][u] = 1;
ans += ask_tree_two(u);
}
if(!vismp[0][post_post]){
vismp[0][post_post] = 1;
ans += ask_zero(post_post);
}
if(!vismp[0][post]){
vismp[0][post] = 1;
ans += ask_zero(post);
}
if(!vismp[1][post]){
vismp[1][post] = 1;
ans += ask_tree_one(post);
}
return ans;
}
else if(pa[pa[u]] == 0){
LL ans = 0;
int fa = pa[u];
int pre = (loop_pos[fa] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[fa] + link_cnt + 1) % link_cnt;
post = loop_link[post];
ans += ask_zero(pre);
ans += ask_zero(post);
ans += ask_zero(fa);
ans += ask_tree_one(fa);
ans += ask_tree_one(u);
ans += ask_tree_two(u);
return ans;
}
else{
LL ans = 0;
ans += ask_zero(pa[pa[u]]);
ans += ask_zero(pa[u]);
ans += ask_tree_one(pa[u]);
ans += ask_tree_one(u);
ans += ask_tree_two(u);
return ans;
}
}
}
void modify(int u,int k,int d){
if(k == 0){
md_zero(u,d);
}
else if(k == 1){
if(pa[u] == 0) // in the loop
{
map<int,int> vismp;
vismp.clear();
int pre = (loop_pos[u] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[u] + link_cnt + 1) % link_cnt;
post = loop_link[post];
vismp[u] = 1;
md_zero(u,d);
md_tree_one(u,d);
if(!vismp[pre]){
vismp[pre] = 1;
md_zero(pre,d);
}
if(!vismp[post]){
vismp[post] = 1;
md_zero(post,d);
}
}
else{
md_zero(pa[u],d);
md_zero(u,d);
md_tree_one(u,d);
}
}
else if(k == 2){
if(pa[u] == 0)// in the loop
{
map<int,int> vismp[3];
vismp[0].clear(),vismp[1].clear(),vismp[2].clear();
int pre_pre = (loop_pos[u] + link_cnt - 2) % link_cnt;
pre_pre = loop_link[pre_pre];
int pre = (loop_pos[u] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[u] + link_cnt + 1) % link_cnt;
post = loop_link[post];
int post_post = (loop_pos[u] + link_cnt + 2) % link_cnt;
post_post = loop_link[post_post];
if(!vismp[0][pre_pre]){
vismp[0][pre_pre] = 1;
md_zero(pre_pre,d);
}
if(!vismp[0][pre]){
vismp[0][pre] = 1;
md_zero(pre,d);
}
if(!vismp[1][pre]){
vismp[1][pre] = 1;
md_tree_one(pre,d);
}
if(!vismp[0][u]){
vismp[0][u] = 1;
md_zero(u,d);
}
if(!vismp[1][u]){
vismp[1][u] = 1;
md_tree_one(u,d);
}
if(!vismp[2][u]){
vismp[2][u] = 1;
md_tree_two(u,d);
}
if(!vismp[0][post_post]){
vismp[0][post_post] = 1;
md_zero(post_post,d);
}
if(!vismp[0][post]){
vismp[0][post] = 1;
md_zero(post,d);
}
if(!vismp[1][post]){
vismp[1][post] = 1;
md_tree_one(post,d);
}
}
else if(pa[pa[u]] == 0){
int fa = pa[u];
int pre = (loop_pos[fa] + link_cnt - 1) % link_cnt;
pre = loop_link[pre];
int post = (loop_pos[fa] + link_cnt + 1) % link_cnt;
post = loop_link[post];
md_zero(pre,d);
md_zero(post,d);
md_zero(fa,d);
md_tree_one(fa,d);
md_tree_one(u,d);
md_tree_two(u,d);
}
else{
md_zero(pa[pa[u]],d);
md_zero(pa[u],d);
md_tree_one(pa[u],d);
md_tree_one(u,d);
md_tree_two(u,d);
}
}
}
void dfs_loop(int u,map<int,int>& mpvis){
for(int e = head[u];e != -1;e = Es[e].next){
int v = Es[e].v;
if(mpvis[v] || belong[v] != loop) continue;
mpvis[v] = 1;
loop_pos[v] = link_cnt;
loop_link[link_cnt++] = v;
dfs_loop(v,mpvis);
}
}
void get_loops(){
map<int,int> mpvis;
int rt = scc[loop][0];
mpvis[rt] = 1;
loop_pos[rt] = link_cnt;
loop_link[link_cnt++] = rt;
dfs_loop(rt,mpvis);
}
void solve(){
init();
loop = idx = sccnum = tot = 0;
memset(vis,0,sizeof(vis));
memset(stk,0,sizeof(stk));
memset(DFN,0,sizeof(DFN));
memset(LOW,0,sizeof(LOW));
memset(belong,0,sizeof(belong));
memset(pa,0,sizeof(pa));
memset(dep,0,sizeof(dep));
memset(bfs_order,0,sizeof(bfs_order));
memset(pos,0,sizeof(pos));
memset(siz,0,sizeof(siz));
memset(loop_link,0,sizeof(loop_link));
memset(belong_tree,0,sizeof(belong_tree));
memset(loop_val,0,sizeof(loop_val));
link_cnt = 0;
for(int i = 0;i < MAXN;i++){
scc[i].clear();
orders[i].clear();
}
scanf("%d",&n);
for(int i = 1;i <= n;i++){
int a,b;
scanf("%d%d",&a,&b);
add_edge(a,b,1);
add_edge(b,a,1);
}
tarjan(1,0);
for(int i = 1;i <= sccnum;++i){
if(scc[i].size() > 1){
loop = i;
}
}
//vector<int> roots;
//roots.clear();
for(int i = 0;i < scc[loop].size();++i){
int rt = scc[loop][i];
bfs(rt);
deal(rt);
if(siz[rt] == 1) belong_tree[rt] = 0;
segs[rt].init(siz[rt]+3);
}
get_loops();
int m;
scanf("%d",&m);
char str[10];
while(m--){
if(str[0] == 'M'){
int u,k,d;
scanf("%d%d%d",&u,&k,&d);
modify(u,k,d);
}
else{
int u,k;
scanf("%d%d",&u,&k);
LL ans;
ans = ask(u,k);
printf("%lld\n",ans);
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
++cas;
solve();
}
return 0;
}