[题解] 紫荆花之恋
题目大意是
一棵树,动态加点,边有边权点有点权r[i]
一个点对(x,y)合法的条件是r[x]+r[y]>=dis(x,y),求每次加点后的合法点对数
题解
每次加点后计算新产生的点对数,是 x 点和[1,x-1]内的点
考虑点分树,d[i]表示 i 到当前分治中心的距离
\[r_i+r_j>=d_i+d_j
\]
\[r_i-d_i>=d_j-r_j
\]
然后暴力跳 x 的父亲,一个容斥,用分治中心 u 的子树内的合法数量减去u的儿子且是x的祖先的合法数量
用平衡树维护每个分治中心的d[j]-r[j]
由于动态加点,点分树采取替罪羊树的思想重构
题解写完了,但是不难发现这个题更重要的是实现过程
分别检查了替罪羊树,倍增,跳父亲求答案的函数,在点分树重构的地方花了很多时间
分别写基本不会错,掺一块儿就觉得很恶心,好像注意力被分散了,也可能是我自身对大码量题目的抵触(其实1.7k就行???),,,
调的时候发现平时根本不会写错的倍增竟然错了两处,还是分两次发现的
都是些零散的细节,比如我要重构x在点分树上的子树,要先断掉fa[x]->x的边,然后再用root和fa[x]连边,可是我忘记断了就出环了
再比如,我要建出点分树同时更新其每个节点的平衡树,跳到根或其父亲就不能跳了,因为祖先的平衡树没有清空
还有一个地方,我是跳父亲更新平衡树的,所以点分治时要先建边再分治到下一层
各自都是些很容易想到和规避的问题,但是同时出现就不是很容易考虑到了
所以先想好细节再码是必要的,但是对于细节很多的题还是不太能全部想到
所以去写大模拟吧,猪国杀.杀蚂蚁.鸭棋都是不错的题呢,,,,
代码
#include<bits/stdc++.h>
using namespace std;
#define il inline
const int N=1e5+11;
const int M=N*150;
const double alp=0.7;
int n,now;
int r[N];
int sum[N],c[N];
int dep[N],pg[N];
int st[19][N];
vector<int> vct[N];
il int max_(int x,int y){return x>y?x:y;}
il int read(){
int s=0;char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s;
}
void init_x(int x,int fa){
if(fa)vct[x].push_back(fa),vct[fa].push_back(x);
sum[x]=sum[fa]+c[x];
dep[x]=dep[fa]+1,st[0][x]=fa;
for(int i=1;i<=pg[dep[x]];++i)st[i][x]=st[i-1][st[i-1][x]];
}
int get_lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=pg[dep[x]-dep[y]];i>=0;--i)if(dep[st[i][x]]>=dep[y])x=st[i][x];
if(x==y)return x;
for(int i=pg[dep[x]];i>=0;--i)if(st[i][x]!=st[i][y])x=st[i][x],y=st[i][y];
return st[0][x];
}
int get_dis(int x,int y){return sum[x]+sum[y]-2*sum[get_lca(x,y)];}
struct sgt_{
int f,rb;
int sta[M],top;
int que[M],tp,tot;
int siz[M],cnt[M],val[M];
int ch[M][2];
il int New(int x){int k=tp?que[tp--]:++tot;siz[k]=cnt[k]=1,val[k]=x;return k;}
void dfs(int x){if(!x)return;dfs(ch[x][0]),sta[++top]=x,dfs(ch[x][1]);}
il bool bad(int x){return siz[x]>=1&&(1.0*siz[ch[x][0]]/siz[x]>=alp||1.0*siz[ch[x][1]]/siz[x]>=alp);}
void init(int x){
top=0;dfs(x);
for(int k,i=1;i<=top;++i){
que[++tp]=k=sta[i];
ch[k][0]=ch[k][1]=0;
siz[k]=cnt[k]=val[k]=0;
}
}
int build(int l,int r){
if(l>r)return 0;
int mid=(l+r)>>1,x=sta[mid];
siz[x]=cnt[x]+siz[ch[x][0]=build(l,mid-1)]+siz[ch[x][1]=build(mid+1,r)];
return x;
}
int rebuild(){top=0,dfs(rb);return build(1,top);}
void ins_(int &i,int x,int fa){
if(!i){i=New(x);return;}++siz[i];++now;
if(val[i]==x){++cnt[i];return;}
if(x<val[i])ins_(ch[i][0],x,i);
else ins_(ch[i][1],x,i);
if(fa&&bad(i))rb=i,f=fa;
}
void ins(int &i,int x){rb=f=0,ins_(i,x,0);if(rb)ch[f][ch[f][1]==rb]=rebuild();}
int qry(int i,int x){
if(!i)return 0;
if(val[i]==x)return cnt[i]+siz[ch[i][0]];
else if(x<val[i])return qry(ch[i][0],x);
else return siz[ch[i][0]]+cnt[i]+qry(ch[i][1],x);
}
}sgt;
struct pot_div{
bool jud[N];
int mx_siz,rot,rb;
int siz[N],f[N];
int rt1[N],rt2[N];
set<int>e[N];
bool bad(int x){return siz[x]>=1&&(1.0*siz[x]/siz[f[x]])>=alp;}
void add(int x,int y){if(!x)return;e[x].insert(y),e[y].insert(x);f[y]=x;}
void init(int i){
e[i].clear();
sgt.init(rt1[i]),sgt.init(rt2[i]);
rt1[i]=rt2[i]=0;
siz[i]=f[i]=0;jud[i]=0;
}
void dfs(int x,int fa){
for(int v : e[x])if(v!=fa)dfs(v,x);init(x);
}
void get_rt(int x,int fa,int now){
siz[x]=1;int mx=0;
for(int v : vct[x]){
if(jud[v]||v==fa)continue;
get_rt(v,x,now);
siz[x]+=siz[v];
mx=max_(mx,siz[v]);
}if((mx=max_(mx,now-siz[x]))<mx_siz)mx_siz=mx,rot=x;
}
void ins(int x,int fa,int zx){
int lst=0;siz[x]=1,add(fa,x);
sgt.ins(rt1[x],-r[x]),sgt.ins(rt2[x],get_dis(fa,x)-r[x]);
for(int ds,i=fa;i;lst=i,i=f[i]){
ds=get_dis(x,i);
if(lst)sgt.ins(rt2[lst],ds-r[x]);
if(i==zx)return;++siz[i];
sgt.ins(rt1[i],ds-r[x]);
}
}
void div(int x,int fa){
jud[x]=1;int tmp;
for(int v : vct[x]){
if(jud[v])continue;
mx_siz=N,get_rt(v,x,siz[v]);
ins(tmp=rot,x,fa);div(tmp,fa);
}
}
int get_ans(int x,int fa){
int ans=0,lst=0;siz[x]=1,add(fa,x);
sgt.ins(rt1[x],-r[x]),sgt.ins(rt2[x],get_dis(fa,x)-r[x]);
for(int ds,i=fa;i;lst=i,i=f[i]){
++siz[i];if(f[f[i]]&&bad(i))rb=f[i];ds=get_dis(x,i);
ans+=sgt.qry(rt1[i],r[x]-ds);
ans-=sgt.qry(rt2[lst],r[x]-ds);
sgt.ins(rt1[i],ds-r[x]);if(lst)sgt.ins(rt2[lst],ds-r[x]);
}if(rb){
int sz=siz[rb];dfs(rb,fa=f[rb]);e[fa].erase(rb);
mx_siz=N,get_rt(rb,fa,sz);
ins(x=rot,fa,fa);div(x,fa);rb=0;
}return ans;
}
}pot_div;
int main(){
// freopen("c.in","r",stdin),freopen("zj1.out","w",stdout);
read(),n=read();
for(int i=1;i<N;++i)pg[i]=log2(i);
long long last_ans=0;
for(int x,i=1;i<=n;++i){
x=read()^(last_ans%(int)1e9);
c[i]=read(),r[i]=read();
init_x(i,x);pot_div.jud[i]=1;
printf("%lld\n",last_ans+=pot_div.get_ans(i,x));
}
}