• 【洛谷P5445】路灯


    题目

    题目链接:https://www.luogu.com.cn/problem/P5445
    一辆自动驾驶的出租车正在 Innopolis 的街道上行驶。该街道上有 (n+1) 个停车站点,它们将街道划分成了 (n) 条路段。每一路段都拥有一个路灯。当第 (i) 个路灯亮起,它将照亮连接第 (i) 与第 (i+1) 个站点的路段。否则这条路段将是黑暗的。
    安全起见,出租车只能在被照亮的路段上行驶。换言之,出租车能从站点 (a) 出发到达站点 (b (a<b)) 的条件是:连接站点 (a)(a+1)(a+2) 与 ,……,(b-1)(b) 的路段都被照亮。
    在经过一些意外故障或修理之后,街道上的路灯可能是亮起的,也可能是熄灭的。
    现在给定 (0) 时刻时,街道上路灯的初始状态。之后 (1,2,ldots,q) 时刻,每时刻会发生下列两种事件之一:

    • ( ext{toggle} i):切换第 (i) 个路灯的状态。具体地说,若路灯原来亮起,则现在将熄灭;若路灯原来熄灭,则现在将亮起。
    • ( ext{query} a b):出租车部门的负责人想知道,从 (0) 时刻起到当前时刻,有多少个时刻满足:出租车能够从站点 (a) 出发到达站点 (b)

    请你帮助出租车部门的负责人回答他们的问题。
    (n,qleq 3 imes 10^3)

    思路

    假设我们把第 (i) 个路灯点亮了,可以用一个 set 维护暗的灯,那么在 set 上可以找到 (i) 左右两边第一个暗的灯,那么自然就得到了可以通行的区间 ([l,r])。这一次操作把 ([l,i])((i,r]) 之间的路打通了。
    考虑映射到二维平面上,也就是把横坐标范围 ([l,i]),纵坐标范围 ((i,r]) 的矩形全部加上 (m-t),其中 (m) 是总时间,(t) 是当前时间。变暗同理,直接把矩形减去 (m-t)。这样如果我们查询 (a,b),只需要求 ((a,b)) 处的值就可以了。注意如果此时 (a,b) 还可以互相到达,答案需要减去 (m-t)
    那么现在的问题就是一个矩形加,单点查询的问题。可以用树状数组套线段树解决。我们把矩形加变为 (4) 次单点修改,在对应的 (log) 棵线段树上单点修改,然后查询的时候查询线段树前缀和即可。
    时空复杂度都是 (O(nlog^2 n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=300010,LG=20,MAXN=30000000;
    int n,m,a[N];
    char ch[10];
    set<int> s;
    
    struct SegTree
    {
    	int tot,lc[MAXN],rc[MAXN];
    	ll sum[MAXN];
    	
    	void pushup(int x)
    	{
    		sum[x]=sum[lc[x]]+sum[rc[x]];
    	}
    	
    	int update(int x,int l,int r,int k,int v)
    	{
    		if (!x) x=++tot;
    		if (l==r)
    		{
    			sum[x]+=v;
    			return x;
    		}
    		int mid=(l+r)>>1;
    		if (k<=mid) lc[x]=update(lc[x],l,mid,k,v);
    			else rc[x]=update(rc[x],mid+1,r,k,v);
    		pushup(x);
    		return x;
    	}
    	
    	int query(int x,int l,int r,int ql,int qr)
    	{
    		if (!x) return 0;
    		if (ql<=l && qr>=r) return sum[x];
    		int mid=(l+r)>>1,ans=0;
    		if (ql<=mid) ans+=query(lc[x],l,mid,ql,qr);
    		if (qr>mid) ans+=query(rc[x],mid+1,r,ql,qr);
    		return ans;
    	}
    }seg;
    
    struct BIT
    {
    	int rt[N];
    	
    	void add(int x,int k,int v)
    	{
    		if (!x || k>n) return;
    		for (int i=x;i<=n;i+=i&-i)
    			rt[i]=seg.update(rt[i],1,n,k,v);
    	} 
    	
    	ll query(int x,int y)
    	{
    		ll ans=0;
    		for (int i=x;i;i-=i&-i)
    			ans=ans+seg.query(rt[i],1,n,1,y);
    		return ans;
    	}
    }bit;
    
    void update(int t,int i)
    {
    	int l=(*(--s.lower_bound(i)))+1;
    	int r=(*s.upper_bound(i))-1;
    	a[i]^=1;
    	if (a[i])
    	{
    		s.erase(s.find(i));
    		bit.add(l,i+1,m-t);
    		bit.add(l,r+2,-m+t);
    		bit.add(i+1,i+1,-m+t); bit.add(i+1,r+2,m-t);
    	}
    	else
    	{
    		s.insert(i);
    		bit.add(l,i+1,-m+t); bit.add(l,r+2,m-t);
    		bit.add(i+1,i+1,m-t); bit.add(i+1,r+2,-m+t);
    	}
    }
    
    void query(int t,int x,int y)
    {
    	ll ans=bit.query(x,y);
    	if (*s.lower_bound(x)>=y) ans-=m-t;
    	printf("%lld
    ",ans);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	n++;
    	for (int i=0;i<=n;i++)
    		s.insert(i);
    	for (int i=1,x;i<n;i++)
    	{
    		scanf("%1d",&x);
    		if (x) update(0,i);
    	}
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%s",ch);
    		if (ch[0]=='t')
    		{
    			int x;
    			scanf("%d",&x);
    			update(i,x);
    		}
    		else
    		{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			query(i,x,y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    python学习之旅-02
    python学习之旅-01
    wps2016热点永久关闭
    一个游戏制作的全过程
    游戏是怎么赚钱的
    游戏数值策划入门教程
    成长系统的设计方法:如何“挖坑”,又不让玩家反感
    游戏数值策划经验篇:从多角度解读游戏经验值设计
    暴雪战斗公式——除法公式的精髓
    游戏数值策划属性篇(二):属性价值评估
  • 原文地址:https://www.cnblogs.com/stoorz/p/14425302.html
Copyright © 2020-2023  润新知