• 【XSY2423】跳蚤(根号分治)


    题面

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    题解

    神奇的分类讨论。

    首先注意到每次所有跳蚤都只会往右跳,也就是说只要某一只跳蚤跳出了 max ⁡ ( r i ) max(r_i) max(ri) 它就不会再有贡献了。(和 火神的鱼 类似)

    R = max ⁡ ( r i ) R=max(r_i) R=max(ri)

    考虑根号分治,将所有的跳蚤分成两类:将 t i > R t_i> sqrt{R} ti>R 的分为第一类,将 t i ≤ R t_ileq sqrt{R} tiR 的分为第二类。

    1. 对于第一类,我们暴力维护这些鱼的位置,因为他们最多跳 R sqrt{R} R 次就会跳出 R R R 了,也就是不会再有贡献了。

      维护的过程可以用树状数组,时间复杂度 O ( q R log ⁡ R ) O(qsqrt R log R) O(qR logR)

    2. 对于第二类,我们考虑对于每一种 t i t_i ti,维护一棵权值线段树,共 R sqrt R R 棵,那么对于每一种 t i t_i ti,根据题目的询问 [ l , r ] [l,r] [l,r],我能还原这些跳蚤一开始应该在那个区间 [ l ′ , r ′ ] [l',r'] [l,r],然后在这颗线段树内查询这个区间。

      R sqrt R R 棵线段树,每棵查询 O ( log ⁡ R ) O(log R) O(logR),总时间 O ( q R log ⁡ R ) O(qsqrt R log R) O(qR logR)

    那么我们就能在 O ( q R log ⁡ R ) O(qsqrt R log R) O(qR logR) 的时间内维护所有操作了。

    代码如下:

    #include<bits/stdc++.h>
    
    #define LN 17
    #define SN 310
    #define N 100010
    #define lc(x) t[x].ch[0]
    #define rc(x) t[x].ch[1]
    #define lowbit(x) (x&-x)
    
    using namespace std;
    
    const int sn=300,n=100000;
    
    struct data
    {
    	int x,t;
    	data(){};
    	data(int a,int b){x=a,t=b;}
    }p[N];
    
    struct Tree
    {
    	int ch[2],sum;
    }t[N*LN];
    
    int q,tot;
    int node,root[SN];
    int c[N];
    
    void add(int x,int y)
    {
    	for(;x<=n;x+=lowbit(x)) c[x]+=y;
    }
    
    int getsum(int x)
    {
    	int ans=0;
    	for(;x;x-=lowbit(x)) ans+=c[x];
    	return ans;
    }
    
    void update(int &k,int l,int r,int x)
    {
    	if(!k) k=++node;
    	t[k].sum++;
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	if(x<=mid) update(lc(k),l,mid,x);
    	else update(rc(k),mid+1,r,x);
    }
    
    int query(int k,int l,int r,int ql,int qr)
    {
    	if(!k) return 0;
    	if(ql<=l&&r<=qr) return t[k].sum;
    	int mid=(l+r)>>1,ans=0;
    	if(ql<=mid) ans+=query(lc(k),l,mid,ql,qr);
    	if(qr>mid) ans+=query(rc(k),mid+1,r,ql,qr);
    	return ans;
    }
    
    int main()
    {
    	scanf("%d",&q);
    	int tim=0;
    	while(q--)
    	{
    		int opt;
    		scanf("%d",&opt);
    		if(opt==1)
    		{
    			int x,t;
    			scanf("%d%d",&x,&t);
    			if(t>sn)
    			{
    				p[++tot]=data(x,t);
    				add(x,1);
    			}
    			else update(root[t],-3e7,3e7,x-tim*t);//还原0时刻这只跳蚤应该在什么位置
    		}
    		if(opt==2)
    		{
    			tim++;
    			int tmp=0;
    			for(int i=1;i<=tot;i++)
    			{
    				add(p[i].x,-1);
    				data now=p[i];
    				now.x+=now.t;
    				if(now.x<=n)
    				{
    					p[++tmp]=now;
    					add(now.x,1);
    				}
    			}
    			tot=tmp;
    		}
    		if(opt==3)
    		{
    			int l,r;
    			scanf("%d%d",&l,&r);
    			int ans=getsum(r)-getsum(l-1);
    			for(int i=1;i<=sn;i++)
    				ans+=query(root[i],-3e7,3e7,l-i*tim,r-i*tim);//还原[l,r]区间在0时刻应该在哪个位置
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    mongodb分片
    mongodb副本集搭建
    mongodb数据导入导出
    mongodb安装、配置
    redis副本集
    redis安装,第一天
    redis常用命令
    mac中安装 RabbitMQ
    Vue常用模块
    nodejs,koa2常用模块
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448638.html
Copyright © 2020-2023  润新知