zoukankan      html  css  js  c++  java
  • Codeforces 1110F(DFS序+线段树)

    题面

    传送门

    分析

    next_id = 1
    id = array of length n filled with -1
    visited = array of length n filled with false
    
    function dfs(v):
        visited[v] = true
        id[v] = next_id
        next_id += 1
        for to in neighbors of v in increasing order:
            if not visited[to]:
                dfs(to)
    

    观察题目中的这段伪代码,发现实际上就是求出每个节点的DFS序,

    注意for to in neighbors of v in increasing order:,要按编号从小到大访问每个节点,所以要对邻接表排序(可以用vector实现)

    对询问离线,每个结点保存由该节点出发所有询问

    第一次DFS,

    求出每个点到根节点的距离,以及DFS序。顺便把每个节点的子树对应的DFS序范围求出,记为l[x],r[x]

    用一棵线段树存储距离,第i个节点存储DFS序为i的树结点到当前询问节点的距离(初始询问节点为1)(注意到求的是到叶子节点的最近距离,所以把非叶子节点的值设为INF

    第二次DFS,

    当DFS到节点x时,线段树中存储的距离恰好是询问节点x到各节点的距离,

    对于每个询问,直接在线段树上查询区间最小值即可

    对从x到儿子y,我们需要更新线段树的值,将x到各节点的距离改成y到各节点的距离

    设x到y的距离为len,发现对于y的子树中的节点,距离会减少len,而对于其他节点,距离会增加len

    由于DFS序的性质,y子树中的节点的DFS序是连续的一段,所以我们只要在线段树上进行区间更新即可

    更新完之后继续DFS y节点,回溯时记得把线段树恢复

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #define maxn 500005
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    vector<pair<int,int> >E[maxn];
    int n,t;
    int cnt=0;
    int l[maxn],r[maxn];
    long long dis[maxn];
    void dfs1(int x,int fa){
    	l[x]=++cnt;
    	for(int i=0;i<E[x].size();i++){
    		int y=E[x][i].first;
    		if(y!=fa){
    			dis[y]=dis[x]+E[x][i].second;
    			dfs1(y,x);
    		}
    	}
    	r[x]=cnt;
    }
    
    struct node{
    	int l;
    	int r;
    	long long mark;
    	long long v;
    }tree[maxn<<2];
    void push_up(int pos){
    	tree[pos].v=min(tree[pos<<1].v,tree[pos<<1|1].v);
    }
    void build(int l,int r,int pos){
    	tree[pos].l=l;
    	tree[pos].r=r;
    	if(l==r){
    		tree[pos].mark=tree[pos].v=0;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,pos<<1);
    	build(mid+1,r,pos<<1|1);
    	push_up(pos);
    }
    void push_down(int pos){
    	if(tree[pos].mark){
    		tree[pos<<1].mark+=tree[pos].mark;
    		tree[pos<<1|1].mark+=tree[pos].mark;
    		tree[pos<<1].v+=tree[pos].mark;
    		tree[pos<<1|1].v+=tree[pos].mark;
    		tree[pos].mark=0;
    	}
    }
    void update(int L,int R,long long v,int pos){
    	if(L<=tree[pos].l&&R>=tree[pos].r){
    		tree[pos].v+=v;
    		tree[pos].mark+=v;
    		return;
    	}
    	push_down(pos);
    	int mid=(tree[pos].l+tree[pos].r)>>1;
    	if(L<=mid)  update(L,R,v,pos<<1);
    	if(R>mid) update(L,R,v,pos<<1|1);
    	push_up(pos);
    }
    long long query(int L,int R,int pos){
    	if(L<=tree[pos].l&&R>=tree[pos].r){
    		return tree[pos].v;
    	}
    	push_down(pos);
    	int mid=(tree[pos].l+tree[pos].r)>>1;
    	long long ans=INF;
    	if(L<=mid)  ans=min(ans,query(L,R,pos<<1));
    	if(R>mid) ans=min(ans,query(L,R,pos<<1|1));
    	return ans;
    }
    
    struct range{
    	int l;
    	int r;
    	long long ans;
    	int id;
    	range(){
    		
    	}
    	range(int L,int R,int i){
    		l=L;
    		r=R;
    		id=i;
    		ans=0;
    	}
    	void debug(){
    		printf("[%d,%d]",l,r);
    	}
    };
    vector<range>q[maxn];
    
    void dfs2(int x,int fa){
    	for(int i=0;i<q[x].size();i++){//处理询问
    		q[x][i].ans=query(q[x][i].l,q[x][i].r,1);
    	}
    	for(int i=0;i<E[x].size();i++){
    		int y=E[x][i].first;
    		int len=E[x][i].second;
    		if(y!=fa){
    			update(l[y],r[y],-len,1);//更新距离
    			if(l[y]>1) update(1,l[y]-1,len,1);//注意边界条件
    			if(r[y]<n) update(r[y]+1,n,len,1); 
    			dfs2(y,x); 
    			update(l[y],r[y],len,1);//记得把线段树恢复成原状
    			if(l[y]>1) update(1,l[y]-1,-len,1);
    			if(r[y]<n) update(r[y]+1,n,-len,1); 
    		}
    	}
    }
    
    long long ans[maxn];
    int main(){
    	int u,v,w,x,ll,rr;
    	scanf("%d %d",&n,&t);
    	for(int i=2;i<=n;i++){
    		scanf("%d %d",&v,&w);
    		E[v].push_back(make_pair(i,w));
    		E[i].push_back(make_pair(v,w));
    	}
    	for(int i=1;i<=n;i++){
    		sort(E[i].begin(),E[i].end());
    	} 
    	for(int i=1;i<=t;i++){
    		scanf("%d %d %d",&x,&ll,&rr);
    		q[x].push_back(range(ll,rr,i)); 
    	}
    	dfs1(1,0);
    	build(1,n,1);
    	for(int i=1;i<=n;i++){
    		if(l[i]==r[i]) update(l[i],l[i],dis[i],1);//如果不是叶子节点,距离要设为INF
    		else update(l[i],l[i],INF,1);
    	}
    	dfs2(1,0);
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<q[i].size();j++){//按照输入顺序输出
    			ans[q[i][j].id]=q[i][j].ans;
    		}
    	}
    	for(int i=1;i<=t;i++){
    		printf("%I64d
    ",ans[i]);
    	}
    }
    
    
  • 相关阅读:
    最近的3个困惑:信守承诺、技术产品先行还是市场销售先行、客户从哪来
    最近的3个困惑:信守承诺、技术产品先行还是市场销售先行、客户从哪来
    详细回复某个CSDN网友,对我的文章和技术实力以及CSDN的吐槽
    详细回复某个CSDN网友,对我的文章和技术实力以及CSDN的吐槽
    2015年工作中遇到的问题:21-30(这10个问题很有价值)
    使用ABAP(ADBC)和Java(JDBC)连接SAP HANA数据库
    C4C和Outlook的集成
    Hybris开发环境的license计算实现
    CRM WebClient UI和Hybris里工作中心跳转的url生成逻辑
    CRM WebUI and Hybris的Product页面标题实现
  • 原文地址:https://www.cnblogs.com/birchtree/p/10357194.html
Copyright © 2011-2022 走看看