• 线段树+Dfs序【p2982】[USACO10FEB]慢下来Slowing down


    Description

    每天Farmer John的N头奶牛(1 <= N <= 100000,编号1…N)从粮仓走向他的自己的牧场。牧场构成了一棵树,粮仓在1号牧场。恰好有N-1条道路直接连接着牧场,使得牧场之间都恰好有一条路径相连。第i条路连接着A_i,B_i,(1 <= A_i <= N; 1 <= B_i <= N)。奶牛们每人有一个私人牧场P_i (1 <= P_i <= N)。粮仓的门每次只能让一只奶牛离开。耐心的奶牛们会等到他们的前面的朋友们到达了自己的私人牧场后才离开。首先奶牛1离开,前往P_1;然后是奶牛2,以此类推。当奶牛i走向牧场P_i时候,他可能会经过正在吃草的同伴旁。当路过已经有奶牛的牧场时,奶牛i会放慢自己的速度,防止打扰他的朋友。 考虑如下的牧场结构(括号内的数字代表了牧场的所有者)。 img

    Input

    第1行 : 一个正整数N

    第2…N行: 第i+1行包括一对正整数A_i,B_i

    第N+1..N+N行: 第 N+i行 包括一个正整数: P_i

    Output

    第一行到第N行:第i行表示第i只奶牛需要被放慢的次数

    线段树维护(dfs)序.

    单点查询.区间修改问题.

    考虑到一头牛到达其私人牧场的时候,经过这个点的路径均会影响到这头牛吃草.(即需要放慢一次速度).

    而,什么样的路径又会经过这个点?通向其子树的点!

    所以对其子树进行区间修改,即([dfn[x],dfn[x]+size[x]-1])

    其中(size[x])代表(x)的子树大小.

    然后每次查询修改的时候记得下放(tag)标记.

    查询即单点查询某个点的(dfs)序即可.

    代码

    #include<cstdio>
    #include<cctype>
    #define ls o<<1
    #define rs o<<1|1
    #define N 100008
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int head[N],tot;
    struct cod{int u,v;}edge[N<<1];
    inline void add(int x,int y)
    {
    	edge[++tot].u=head[x];
    	edge[tot].v=y;
    	head[x]=tot;
    }
    int dfn[N],idx,size[N];
    void dfs(int u,int fa)
    {
    	dfn[u]=++idx;size[u]=1;
    	for(R int i=head[u];i;i=edge[i].u)
    	{
    		if(edge[i].v==fa)continue;
    		dfs(edge[i].v,u);
    		size[u]+=size[edge[i].v];
    	}
    }
    int tr[N<<2],n;
    inline void down(int o)
    {
    	if(tr[o])
    	{
    		tr[ls]+=tr[o];
    		tr[rs]+=tr[o];
    		tr[o]=0;
    		return;
    	}
    }
    void change(int o,int l,int r,int x,int y)
    {
    	if(x<=l and y>=r){tr[o]++;return;}
    	down(o);
    	int mid=(l+r)>>1;
    	if(x<=mid)change(ls,l,mid,x,y);
    	if(y>mid)change(rs,mid+1,r,x,y);
    }
    int query(int o,int l,int r,int x)
    {
    	if(l==r)return tr[o];
    	down(o);
    	int mid=(l+r)>>1;
    	if(x<=mid)return query(ls,l,mid,x);
    	return query(rs,mid+1,r,x);	
    }
    int main()
    {
    	in(n);
    	for(R int i=1,x,y;i<n;i++)
    	{
    		in(x),in(y);
    		add(x,y),add(y,x);
    	}
    	dfs(1,0);
    	for(R int i=1,x;i<=n;i++)
    	{
    		in(x);
    		printf("%d
    ",query(1,1,n,dfn[x]));
    		change(1,1,n,dfn[x],dfn[x]+size[x]-1);
    	}
    }
    
  • 相关阅读:
    Java并发/多线程-线程池的使用
    pam详解
    chrony时间同步服务
    网站每日UV数据指标去重统计
    阻塞式发送邮件
    待办事项-redis
    解决Windows7、Windows10 ping不通的问题
    redis序列化和反序列化的操作-(以前咋操作我都忘记了)
    秒杀活动下的公平队列抢购机制
    控制某个字段不在页面展示
  • 原文地址:https://www.cnblogs.com/-guz/p/9846264.html
Copyright © 2020-2023  润新知