zoukankan      html  css  js  c++  java
  • 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT

    【BZOJ3435】[Wc2014]紫荆花之恋

    Description

    强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。  
    我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。 

    Input

    共有 n + 2 行。 
    第一行包含一个正整数,表示测试点编号。 
    第二行包含一个正整数 n ,表示总共要加入的节点数。 
    我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为0。 
    接下来 n 行中第 i 行有三个数 ai, bi, ri,表示节点  i  的父节点的编号为 ai xor (last_ans mod 10^9)   (其中xor 表示异或,mod  表示取余,数据保证这样操作后得到的结果介于 1到i  –  1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感受能力值为r!。 
    注意 a1 = c1 = 0,表示 1 号点是根节点,对于 i > 1,父节点的编号至少为1。

    Output

    包含 n 行,每行输出1 个整数, 表示加入第 i 个点之后,树上有几对朋友。

    Sample Input

    0
    5
    0 0 6
    1 2 4
    0 9 4
    0 5 5
    0 2 4

    Sample Output

    0
    1
    2
    4
    7

    HINT

    1<=Ci<=10000
    Ai<=2*10^9
    Ri<=10^9
    N<=100000

    题解:在GXZ的蛊惑下,特地去学了一发SBT~

    显然要将题中的式子拆一下:dis(i,j)<=ri+rj  -> dis(i,lca)+dis(j,lca)<=ri+rj -> dis(i,lca)-ri<=rj-dis(j,lca)。

    所以我们对点分树上的每个节点都维护一个SBT记录所有dis(i,x)-ri,然后每次加点时,在点分树上到根的路径上的每个点的SBT都查一下就行了。由于有重复计算,所以对于每个点我们还要维护一个SBT记录所有dis(i,fa[x])-ri,查询时减去即可。

    但是动态加点怎么办?将点分树变成替罪的即可。

    其实代码并不是特别长,如果TLE了一定是写挂了~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    typedef long long ll;
    const int maxn=100010;
    const ll mod=1000000000;
    int n,m,tot,cnt,mn,root;
    ll ans;
    struct sbt
    {
    	int siz,ch[2],val;
    }t[20000005];
    vector<int> ch[maxn];
    int r[maxn],f[19][maxn],siz[maxn],dep[maxn],head[maxn],next[maxn<<1],to[maxn<<1],vis[maxn],p[maxn];
    int r1[maxn],r2[maxn],fa[maxn],dd[maxn],Log[maxn];
    queue<int> q;
    int mem;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void pushup(int x)	{t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;}
    void rotate(int &x,int d)
    {
    	int y=t[x].ch[d];
    	t[x].ch[d]=t[y].ch[d^1],t[y].ch[d^1]=x;
    	pushup(x),pushup(y),x=y;
    }
    void maintain(int &x,int d)
    {
    	if(t[t[t[x].ch[d]].ch[d]].siz>t[t[x].ch[d^1]].siz)
    		rotate(x,d);
    	else	if(t[t[t[x].ch[d]].ch[d^1]].siz>t[t[x].ch[d^1]].siz)
    		rotate(t[x].ch[d],d^1),rotate(x,d);
    	else	return;
    	maintain(t[x].ch[0],0),maintain(t[x].ch[1],1);
    	maintain(x,0),maintain(x,1);
    }
    void insert(int &x,int y)
    {
    	if(!x)
    	{
    		mem--;
    		x=q.front(),q.pop();
    		t[x].siz=1,t[x].val=y,t[x].ch[0]=t[x].ch[1]=0;
    		return ;
    	}
    	int d=(y>=t[x].val);
    	t[x].siz++,insert(t[x].ch[d],y);
    	maintain(x,d);
    }
    int query(int x,int y)
    {
    	if(!x)	return 0;
    	if(t[x].val<=y)	return query(t[x].ch[1],y)+1+t[t[x].ch[0]].siz;
    	return query(t[x].ch[0],y);
    }
    void del(int &x)
    {
    	if(!x)	return ;
    	mem++;
    	del(t[x].ch[0]),del(t[x].ch[1]),t[x].siz=t[x].val=0,q.push(x),x=0;
    }
    void getrt(int x,int fa)
    {
    	siz[x]=1;
    	int i,tmp=0;
    	for(i=head[x];i!=-1;i=next[i])	if(to[i]!=fa&&vis[to[i]]==2)
    		getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
    	tmp=max(tmp,tot-siz[x]);
    	if(tmp<mn)	mn=tmp,root=x;
    }
    void solve(int x)
    {
    	vis[x]=1;
    	for(int i=head[x];i!=-1;i=next[i])	if(vis[to[i]]==2)
    		tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[root]=x,solve(root);
    }
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    int lca(int a,int b)
    {
    	if(dd[a]<dd[b])	swap(a,b);
    	int i;
    	for(i=Log[dd[a]-dd[b]];i>=0;i--)	if(dd[f[i][a]]>=dd[b])	a=f[i][a];
    	if(a==b)	return b;
    	for(i=Log[dd[a]];i>=0;i--)	if(f[i][a]!=f[i][b])	a=f[i][a],b=f[i][b];
    	return f[0][a];
    }
    int dis(int a,int b)
    {
    	return dep[a]+dep[b]-2*dep[lca(a,b)];
    }
    int main()
    {
    	rd(),n=rd();
    	memset(head,-1,sizeof(head));
    	int i,j,a,b,u,last,flast;
    	mem=20000000;
    	for(i=1;i<=20000000;i++)	q.push(i);
    	rd(),rd(),r[1]=rd(),siz[1]=1,dd[1]=1,ch[1].push_back(1),insert(r1[1],-r[1]);
    	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
    	printf("0
    ");
    	for(i=2;i<=n;i++)
    	{
    		a=rd()^(ans%mod),b=rd(),r[i]=rd();
    		add(a,i),add(i,a),dep[i]=dep[a]+b,dd[i]=dd[a]+1;
    		f[0][i]=a,fa[i]=a;
    		for(j=1;j<=Log[dd[i]];j++)	f[j][i]=f[j-1][f[j-1][i]];
    		for(last=0,u=i;u;u=fa[u])
    		{
    			ans+=query(r1[u],r[i]-dis(i,u));
    			ch[u].push_back(i),insert(r1[u],dis(i,u)-r[i]),siz[u]++;
    			if(fa[u])
    			{
    				ans-=query(r2[u],r[i]-dis(i,fa[u]));
    				insert(r2[u],dis(i,fa[u])-r[i]);
    			}
    			if(fa[u]&&siz[u]*1.0>(siz[fa[u]]+1)*0.88)	last=fa[u];
    		}
    		if(last)
    		{
    			flast=fa[last],vis[flast]=3;
    			for(p[0]=j=0;j<(int)ch[last].size();j++)	p[++p[0]]=ch[last][j];
    			for(j=1;j<=p[0];j++)	ch[p[j]].clear(),del(r1[p[j]]),del(r2[p[j]]),vis[p[j]]=2;
    			tot=p[0],mn=1<<30,getrt(last,0),fa[root]=flast,solve(root);
    			for(j=1;j<=p[0];j++)
    			{
    				for(u=p[j];u!=flast;u=fa[u])
    				{
    					ch[u].push_back(p[j]);
    					insert(r1[u],dis(p[j],u)-r[p[j]]);
    					if(fa[u])	insert(r2[u],dis(p[j],fa[u])-r[p[j]]);
    				}
    			}
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现业务
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 开发流程
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 报表系统集成说明
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 处理报表
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据访问
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 分布式应用
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现插件
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 对象设计器使用帮助
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据层开发
    Jquery 中的CheckBox、 RadioButton、 DropDownList、CheckBoxList、RadioButtonList的取值赋值
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7452237.html
Copyright © 2011-2022 走看看