zoukankan      html  css  js  c++  java
  • BZOJ2827 千山鸟飞绝

    题意

    话说有一天doyouloveme和vfleaking到山里玩。谁知doyouloveme刚刚进山,所有的鸟儿竟被他的神犇气场给惊得全部飞走了。vfleaking顿时膜拜不已。
    
    这时鸟王用鸟语说道:“!@#$……?” 安抚了一下众鸟的情绪。鸟王生性好斗,作出了一个决定——要排鸟布阵把刚才吓到它们的人类赶出山去。
    
    每只鸟都有一个编号,都有一个威武值。每秒钟鸟王都会发一个命令,编号为v的鸟飞到(x,y)去(坐标系原点是山顶,坐标单位为鸟爪)。鸟飞得很快,一秒之内就飞到了,可以看作是瞬间移动。如果编号为v的鸟和编号为u的鸟某一时刻处在同一位置,它们就会互相鼓励,增加各自的士气值和团结值。一只鸟的士气值等于此刻与它处在同一位置的鸟中的威武值的最大值,团结值等于此刻与它处在同一位置的鸟的只数。如果每一时刻都没有鸟与它处在同一位置,则士气值和团结值都为0。要注意自己不能鼓励自己,计算士气值和团结值时不能算上自己。
    
    t秒钟后,doyouloveme目测出了现在每只鸟的战斗力,于是感叹了一句:“不妙,我们得走了。”
    
    正所谓团结的鸟儿一个顶俩,所以doyouloveme这样描述战斗力:一只鸟战斗力值等于它在0到t秒中士气值的最大值与团结值的最大值的乘积。注意不是乘积的最大值,而是最大值的乘积。
    
    vfleaking很想知道现在每只鸟的战斗力,但是他当然不会啦,于是他把这个任务交给了你来完成。
    

    (1≤n≤30000,0≤t≤300000)

    分析

    当然是平衡树。

    这题的精华在于标记。标记有两个,一个是历史最大士气值,另一个是历史最大团结值。标记的作用域是子树,奇怪的写法是pushdown的时候要更新外面的答案,然后下放,清除。

    平衡树的写法有些奇怪,以下标为序。

    插入的时候要更新标记和答案,删除的时候什么都不用做,因为pushdown把事情干完了。

    值得注意的是最后查询的时候要把标记全部清空,简便的方法是把所有节点都删除掉。

    时间复杂度(O(n log n + t log n))

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read()
    {
    	rg T data=0;
    	rg int w=1;
    	rg char ch=getchar();
    	while(!isdigit(ch))
    	{
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    	{
    		data=data*10+ch-'0';
    		ch=getchar();
    	}
    	return data*w;
    }
    template<class T>il T read(rg T&x)
    {
    	return x=read<T>();
    }
    typedef long long ll;
    
    co int N=3e4+1;
    int val[N];
    int hmax[N],hsiz[N]; // ans
    int bl[N];
    
    int root[N*11];
    namespace T
    {
    	int ch[N][2],siz[N],pri[N]; // edit 2
    	int max[N],hmax[N],hsiz[N]; // tag
    	
    	void init(int x)
    	{
    		ch[x][0]=ch[x][1]=0,siz[x]=1,pri[x]=rand();
    		max[x]=val[x],hmax[x]=hsiz[x]=0;
    	}
    	
    	void pushup(int x)
    	{
    		siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
    		max[x]=std::max(max[ch[x][0]],std::max(val[x],max[ch[x][1]]));
    	}
    	
    	void pushdown(int x)
    	{
    		if(hmax[x])
    		{
    			::hmax[x]=std::max(::hmax[x],hmax[x]);
    			hmax[ch[x][0]]=std::max(hmax[ch[x][0]],hmax[x]);
    			hmax[ch[x][1]]=std::max(hmax[ch[x][1]],hmax[x]);
    			hmax[x]=0;
    		}
    		if(hsiz[x])
    		{
    			::hsiz[x]=std::max(::hsiz[x],hsiz[x]);
    			hsiz[ch[x][0]]=std::max(hsiz[ch[x][0]],hsiz[x]); 
    			hsiz[ch[x][1]]=std::max(hsiz[ch[x][1]],hsiz[x]);
    			hsiz[x]=0; 
    		}
    	}
    	
    	int merge(int x,int y)
    	{
    		if(!x||!y)
    			return x+y;
    		if(pri[x]>pri[y])
    		{
    			pushdown(x);
    			ch[x][1]=merge(ch[x][1],y);
    			pushup(x);
    			return x;
    		}
    		else
    		{
    			pushdown(y);
    			ch[y][0]=merge(x,ch[y][0]);
    			pushup(y);
    			return y;
    		}
    	}
    	
    	void split(int x,int p,int&l,int&r)
    	{
    		if(!x)
    		{
    			l=r=0;
    			return;
    		}
    		if(x<=p)
    		{
    			l=x;
    			pushdown(l);
    			split(ch[l][1],p,ch[l][1],r);
    			pushup(l);
    		}
    		else
    		{
    			r=x;
    			pushdown(r);
    			split(ch[r][0],p,l,ch[r][0]);
    			pushup(r);
    		}
    	}
    	
    	void Insert(int&t,int x)
    	{
    		::hmax[x]=std::max(::hmax[x],max[t]);
    		::hsiz[x]=std::max(::hsiz[x],siz[t]);
    		hmax[t]=std::max(hmax[t],val[x]);
    		hsiz[t]=std::max(hsiz[t],siz[t]);
    		int l,r;
    		split(t,x,l,r);
    		t=merge(l,merge(x,r));
    	}
    	
    	void Delete(int&t,int x)
    	{
    		int l,m,r;
    		split(t,x,m,r);
    		split(m,x-1,l,m);
    		assert(m==x);
    		t=merge(l,r);
    		init(x); // edit 1
    	}
    }
    
    typedef std::pair<int,int> pii;
    std::map<pii,int> M;
    int id;
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	int n;
    	read(n);
    	for(int i=1;i<=n;++i)
    	{
    		pii pos;
    		read(val[i]),read(pos.first),read(pos.second);
    		if(!M[pos])
    			M[pos]=++id;
    		bl[i]=M[pos];
    		T::init(i);
    		T::Insert(root[bl[i]],i);
    	}
    	int t;
    	read(t);
    	while(t--)
    	{
    		int i;
    		pii pos;
    		read(i),read(pos.first),read(pos.second);
    		T::Delete(root[bl[i]],i);
    		if(!M[pos])
    			M[pos]=++id;
    		bl[i]=M[pos];
    		T::Insert(root[bl[i]],i);
    	}
    	for(int i=1;i<=n;++i)
    	{
    		T::Delete(root[bl[i]],i);
    		printf("%lld ",(ll)hmax[i]*hsiz[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Hbase学习02-API操作
    Hbase学习01-shell操作
    09 | 普通索引和唯一索引,应该怎么选择?
    08 | 事务到底是隔离的还是不隔离的?
    07 | 行锁功过:怎么减少行锁对性能的影响?
    06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
    05 | 深入浅出索引(下)
    04 | 深入浅出索引(上)
    03 | 事务隔离:为什么你改了我还看不见?
    02 | 日志系统:一条SQL更新语句是如何执行的?
  • 原文地址:https://www.cnblogs.com/autoint/p/10310684.html
Copyright © 2011-2022 走看看