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;
}
静渊以有谋,疏通而知事。