牛客 H 华华和月月种树(dfs序+线段树)

链接:https://ac.nowcoder.com/acm/contest/392/H
来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
华华看书了解到,一起玩养成类的游戏有助于两人培养感情。所以他决定和月月一起种一棵树。因为华华现在也是信息学高手了,所以他们种的树是信息学意义下的。
华华和月月一起维护了一棵动态有根树,每个点有一个权值。刚开存档的时候,树上只有 0 号节点,权值为 0 。接下来有两种操作:
操作 1:输入格式
1 i
1 i,表示月月氪金使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。
操作 2:输入格式
2 i a
2 i a,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。
但是月月有时会检查华华有没有认真维护这棵树,会作出询问:
询问 3:输入格式
3 i
3 i,华华需要给出 i 节点此时的权值。
华华当然有认真种树了,不过还是希望能写个程序以备不时之需。
输入描述:
第一行一个正整数M,接下来M行,每行先输入一个正整数O表示操作类型,再输入一个非负整数i表示操作或询问的节点编号,如果O=2,再输入一个正整数a。
输出描述:
对于每个询问3,输出一个非负整数表示询问的答案。
示例1
输入
复制
9
1 0
2 0 1
3 0
3 1
1 0
1 1
2 0 2
3 1
3 3
输出
复制
1
1
3
2
备注
1≤M≤4×1e5,保证操作1的数量不超过1e5,保证操作2中的参数a满足1≤a≤999

解析:

先离线操作,建好树,然后用vis数组存储这棵树的dfs序,即i号点被搜到的时间为vis[i],因为同一颗子树内的vis总是连续的,
所以当一个点被修改时,其子树上的所有节点(vis[i],vis[i]+size[vis[i]]-1)这一段连续的区间就会被修改,
用线段树就可以处理了
这时候考虑一个问题
如果在这个点产生(1操作)之前就被2操作了怎么办?
其实这时候只需要把这个点置为0即可,这样就能抵消前面的影响。
刚开始写了一份java代码,发现还是会出现数组溢出的问题,然后改成c++就过了。也不知道怎么回事
两份代码都贴出来吧

希望看出错误的大佬可以指正,多谢。
c++版、

#include

using namespace std;

	const int N=400000+10;
	int head[N*4],nex[N*4],to[N*4],vis[N*4],siz[N*4],tree[N*4],lazy[N*4];
	static int now=0,cnt=0,cnt1=0;
	struct node{
	    int x,y,z;
	}ss[N];

	static void add(int x ,int y) {
		now++;
		to[now]=y;
		nex[now]=head[x];
		head[x]=now;
	}
	static void dfs(int x,int pre) {
		vis[x]=++cnt1;
		siz[x]=1;
		for(int i=head[x];i!=0;i=nex[i]) {
			int y=to[i];
			if(vis[y]==0) {
				dfs(y,x);
				siz[x]+=siz[y];
			}
		}
	}
	    void pushdown(int x) {
		if(lazy[x]!=0) {
			tree[x]+=lazy[x];
			lazy[x<<1]+=lazy[x];
			lazy[x<<1|1]+=lazy[x];
			lazy[x]=0;
		}
	}
	int fi(int i,int l,int r,int ch) {
		pushdown(ch);
		if(l==r) {
			return tree[ch];
		}
		int m=(l+r)/2;
		if(i<=m) {
			return fi(i,l,m,ch<<1);
		}
		else return fi(i,m+1,r,ch<<1|1);
	}
    void change(int y,int l,int r,int ch) {
		pushdown(ch);
		if(l==r) {
			tree[ch]=0;
			return ;
		}
		int m=(l+r)/2;
		if(y<=m)
			change(y,l,m,ch<<1);
		else
			change(y,m+1,r,ch<<1|1);
	}
	void add1(int l, int r, int z,int L,int R,int ch) {
		pushdown(ch);
		if(L>=l&&R<=r) {
			lazy[ch]+=z;
			return;
		}
		int m=(L+R)/2;
		if(l<=m) add1(l,r,z,L,m,ch<<1);
		if(r>m) add1(l,r,z,m+1,R,ch<<1|1);
	}
int main()
{
    ios::sync_with_stdio(false);
    int m;
    cin>>m;
    for(int i=0;i<m;i++){
        int x,y,z;
        cin>>x>>y;
        if(x==1){
            add(y,++cnt);
        }
        else if(x==2){
            cin>>z;
            ss[i].z=z;
        }
        ss[i].x=x;
        ss[i].y=y;
    }

		dfs(0,-1);
		int now1=1;
		for(int i=0;i<m;i++) {
			if(ss[i].x==1) {
				change(vis[now1],1,cnt1,1);
				now1++;
			}
			else if(ss[i].x==2) {
				add1(vis[ss[i].y],vis[ss[i].y]+siz[ss[i].y]-1,ss[i].z,1,cnt1,1);
			}
			else if(ss[i].x==3) {
                cout<<fi(vis[ss[i].y],1,cnt1,1)<<endl;
				//System.out.println(fi(vis[ss[i].y],1,cnt1,1));
			}
		}
		return 0;
}




java版

package myproject;

import java.io.BufferedReader;
import java.io.*;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
class  S implements Comparable<S>
{
	int x,y,z;
	public S(int x,int y,int z) {
		this.x=x;
		this.y=y;
		this.z=z;
	}
	public int compareTo(S o) {
		return 0;
	}
}
public class Main {
	static int N=400000+10;
	static S []ss =new S [N*4];
	static int []head=new int [N*4];
	static int []next =new int [N*4];
	static int []to= new int [N*4];
	static int []vis=new int [N*4];
	static int []size=new int [N*4];
	static int[]tree=new int [N*5];
	static int []lazy=new int [N*5];
	static int now=0,cnt=0,cnt1=0;
	static void add(int x ,int y) {
		now++;
		to[now]=y;
		next[now]=head[x];
		head[x]=now;
	}
	static void dfs(int x,int pre) {
		vis[x]=++cnt1;
		size[x]=1;
		for(int i=head[x];i!=0;i=next[i]) {
			int y=to[i];
			if(vis[y]==0) {
				dfs(y,x);
				size[x]+=size[y];
			}
		}
	}
	public static void main(String []args) throws IOException {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
		String str=br.readLine();
		int m=Integer.parseInt(str);
		for(int i=0;i<m;i++) {
			str=br.readLine();
			String []s =str.split(" ");
			int x=Integer.parseInt(s[0]);
			int y=Integer.parseInt(s[1]);
			int z=0;
			if(x==1) {
				add(y,++cnt);
			}
			if(x==2) {
				z=Integer.parseInt(s[2]);
			}
			ss[i]=new S(x,y,z);
		}

		dfs(0,-1);
		int now1=1;
		for(int i=0;i<m;i++) {
			if(ss[i].x==1) {
				change(vis[now1],1,cnt1,1);
				now1++;
			}
			else if(ss[i].x==2) {
				add1(vis[ss[i].y],vis[ss[i].y]+size[ss[i].y]-1,ss[i].z,1,cnt1,1);
			}
			else if(ss[i].x==3) {
				System.out.println(fi(vis[ss[i].y],1,cnt1,1));
			}
		}
	}
	static void pushdown(int x) {
		if(lazy[x]!=0) {
			tree[x]+=lazy[x];
			lazy[x<<1]+=lazy[x];
			lazy[x<<1|1]+=lazy[x];
			lazy[x]=0;
		}
	}
	private static int fi(int i,int l,int r,int ch) {
		pushdown(ch);
		if(l==r) {
			return tree[ch];
		}
		int m=(l+r)/2;
		if(i<=m) {
			return fi(i,l,m,ch<<1);
		}
		else return fi(i,m+1,r,ch<<1|1);
	}
	private static void change(int y,int l,int r,int ch) {
		pushdown(ch);
		if(l==r) {
			tree[ch]=0;
			return ;
		}
		int m=(l+r)/2;
		if(y<=m) 
			change(y,l,m,ch<<1);
		else 
			change(y,m+1,r,ch<<1|1);
	}
	private static void add1(int l, int r, int z,int L,int R,int ch) {
		pushdown(ch);
		if(L>=l&&R<=r) {
			lazy[ch]+=z;
			return;
		}
		int m=(L+R)/2;
		if(l<=m) add1(l,r,z,L,m,ch<<1);
		if(r>m) add1(l,r,z,m+1,R,ch<<1|1);
	}
}



你可能感兴趣的:(线段树)