​http://www.elijahqi.win/2018/03/01/bzoj3435/​​​
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

被卡常了 treap 在uoj妥妥过不去 瞎搞的splay在uoj有时可过有时不可过 在luogu treap 也是一会能过 一会不能过 bzoj是总时限 还是比较稳的..放弃卡常了.. 尝试避免很多递归操作 反而变慢了??

考虑暴力的话 前40写两个splay也是可以做的

#include<cstdio>
#include<algorithm>
#define N 110000
#define ll long long
#define mod 1000000000
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}ll ans;int n;
struct node{
int fa[N],c[N][2],size[N],cnt,root;ll tag[N],v[N];
inline void update(int x){size[x]=size[c[x][0]]+size[c[x][1]]+1;}
inline void pushdown(int x){
if (!tag[x]) return;
int l=c[x][0],r=c[x][1];
if (l) tag[l]+=tag[x],v[l]+=tag[x];
if (r) tag[r]+=tag[x],v[r]+=tag[x];tag[x]=0;
}
inline void rotate(int x,int &tar){
int y=fa[x],z=fa[y];
if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
int l=c[y][1]==x,r=l^1;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
while(x!=tar){
int y=fa[x],z=fa[y];
if (y!=tar){
if (c[z][0]==y^c[y][0]==x) rotate(x,tar);else rotate(y,tar);
}rotate(x,tar);
}
}
inline void insert2(int &x,ll vv,int f){
if (!x) {x=++cnt;fa[cnt]=f;v[x]=vv;size[x]=1;return;}
pushdown(x);
if (vv<=v[x]) insert2(c[x][0],vv,x);else insert2(c[x][1],vv,x);
}
inline void insert1(ll vv){
insert2(root,vv,0);splay(cnt,root);
}
inline int query(int x,ll vv){
if (!x) return 0;pushdown(x);int l=c[x][0],r=c[x][1];
if (vv>=v[x]) return size[l]+1+query(r,vv);
return query(c[x][0],vv);
}
inline void print(int x){
pushdown(x);
if (c[x][0]) print(c[x][0]);
printf("%d:%lld ",x,v[x]);
if (c[x][1]) print(c[x][1]);
}
inline void print1(){print(root);}
inline void change(ll x){v[root]+=x;tag[root]+=x;}
}tree1,tree2;//tree1 维护左端点开始 tree2维护右端点开始
inline void solve2(){
n=read();puts("0");ll fa=read(),a=read(),r=read();ll lastans=0;ll len=0;
tree1.insert1(-r);tree2.insert1(-r);int l=1;
for (int i=2;i<=n;++i){
fa=read()^(lastans%mod),a=read(),r=read();len+=a;
if (fa==l){
ans+=tree2.query(tree2.root,r-a);lastans=ans;printf("%lld\n",ans);
l=i;tree2.change(a);tree2.insert1(-r);
tree1.insert1(len-r);
}else{
ans+=tree1.query(tree1.root,r-a);lastans=ans;printf("%lld\n",ans);
tree1.change(a);tree1.insert1(-r);
tree2.insert1(len-r);
}
//puts("1");tree1.print1();puts("");puts("2");tree2.print1();puts("");
}
}
struct node1{
int y,z,next;
}data[2200];
ll num,h[1100],r[1100],cul;ll dis[1100];
inline void insert1(int x,int y,int z){
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].z=z;data[num].next=h[y];h[y]=num;
}
inline void dfs(int x,int fa){
if (r[x]-dis[x]>=cul) ++ans;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if (y==fa) continue;dis[y]=dis[x]+z;dfs(y,x);
}
}
inline void solve1(){
n=read();puts("0");int fa=read(),a=read(),R=read();r[1]=R;ll lastans=0;
for (int i=2;i<=n;++i){
fa=read()^lastans;a=read();R=read();cul=a-R;
dis[fa]=0;dfs(fa,0);insert1(fa,i,a);r[i]=R;lastans=ans;printf("%lld\n",ans);
}
}
int main(){
// freopen("uoj55.in","r",stdin);
//freopen("uoj.out","w",stdout);
int iid=read();
if (iid<=4) solve1();else if (iid<=8) solve2();
return 0;
}

怎么搞 考虑的是我把这个式子拆成两个条件显然我就可以静态维护这个东西了 要不然总会有东西在变化 设dis[i]+dis[j]<=r[i]+r[j] 那么 考虑我当前节点i会和哪些点产生贡献 将式子变形

dis[j]-r[j]<=r[i]-dis[i] 显然求一下我r[i]比哪些点大即可 那么考虑做法在点分树上每个节点维护一个splay 然后每次统计答案的时候直接从点分树叶子节点从下往上递推即可 每次判定下比我晓得有多少个 但是这样可能存在问题 做点分治的时候都知道这样的话会存在两个来自同一子树的点对答案做出贡献 所以不妨考虑容斥 直接暴力询问这个贡献 然后再把在同一个子树里的减去即可

所以设rtf表示我当前这个节点会对上面节点产生多少减去的贡献的值的平衡树的根rt 表示我这个点分节点管辖的店的这个dis[j]-r[j]的平衡树的根

这样的话可能产生不平衡的情况 比如一条链就需要替罪羊树思想 每次如果子树大小太多了就暴力重构点分树 均摊复杂度log(n)

设par[x][i]表示 当前处于x号节点(均包括自己) 我点分树上第i个祖先是多少 这个i越小 对应点分树上深度越浅的点 dis_[x][i]同理 对应的是点分树上的那个点到我当前点的距离 son[x]表示我当前这个点管辖的所有儿子 所以我每次查答案 和修改点分树中splay/treap的时候即可用Log时间复杂度往上跳 到达根部 统计答案也同理计算Log次即可

然后,再从深度浅到深遍历所有祖先结点,找到第一个不满足平衡条件的点,将它的子树中的所有点进行一次静态的点分治,相当于重建点分树

这题因为经常要重构 并且插入量也非常大 需要使用treap才可过 可是我还是T了qwq

我splay的乱搞 大概也是像替罪羊一样 平衡达到多少时 像treap一样旋转一下 使得不必要每次插入有需要旋转到根减少复杂度

uoj extra5也过了 但估计再出数据怎么都能把这种方法卡死 另外注意在重构点分树的时候注意不要搜索出这块区域

不知怎么qwq 我很多东西写成非递归 反而慢了很多 非递归部分在一下的注释中均有出现 可以参考qwq

点分+splay乱搞+替罪羊树思想 uoj跑AC过qwq

#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#define N 110000
#define M 4000010
#define mod 1000000000
#define ll long long
#define alpha 0.8
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
ll ans;bool visit[N];
int h[N],n,num,r[N],dis[N],f[N],root,sum,rt[N],rt_f[N],cnt,sz[N];
int size[M],fa[M],nm[M],c[M][2],v[M];
struct node{
int y,z,next;
}data[N<<1];
vector<int>dis_[N],par[N],son[N];queue<int>rec;
inline void insert_edge(int x,int y,int z){
data[++num].y=y;data[num].next=h[x];data[num].z=z;h[x]=num;
data[++num].y=x;data[num].next=h[y];data[num].z=z;h[y]=num;
}
inline int newnode(){
if (rec.empty()) return ++cnt;int x=rec.front();rec.pop();return x;
}
inline void print(int x){
if (c[x][0]) print(c[x][0]);
printf("%d %d ",v[x],nm[x]);
if (c[x][1]) print(c[x][1]);
}
inline void update(int x){
size[x]=size[c[x][0]]+nm[x]+size[c[x][1]];
}
inline void rotate(int x,int &tar){
int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
while(x!=tar){
int y=fa[x],z=fa[y];
if (y!=tar){
if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
}rotate(x,tar);
}
}
inline int qk(int x,int vv){
if (!x) return 0;
if(vv<v[x]) return qk(c[x][0],vv);
if (vv==v[x]) return size[c[x][0]]+nm[x];
return size[c[x][0]]+nm[x]+qk(c[x][1],vv);
}
inline void insert1(int &x,int vv,int f,int &rot){
if (!x) {x=newnode();fa[x]=f;size[x]=nm[x]=1;v[x]=vv;return;}
if(vv==v[x]) {++nm[x],++size[x];return;}//,splay(x,rot)}splay(x,rot);
if(vv<v[x]) {
insert1(c[x][0],vv,x,rot);update(x);if (size[x]<=30) return;
if(size[c[x][0]]>size[x]*0.7) splay(c[x][0],x);
}
else {
insert1(c[x][1],vv,x,rot);update(x);if (size[x]<=30) return;
if(size[c[x][1]]>size[x]*0.7) splay(c[x][1],x);
}
}
inline void del(int &x){
if (!x) return;
rec.push(x);del(c[x][0]);del(c[x][1]);size[x]=nm[x]=fa[x]=c[x][0]=c[x][1]=v[x]=0;x=0;
}
inline void get_root(int x,int fa){
sz[x]=1;f[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa||visit[y]) continue;
get_root(y,x);sz[x]+=sz[y];f[x]=max(f[x],sz[y]);
}f[x]=max(f[x],sum-sz[x]);
if (f[root]>f[x]) root=x;
}
inline void dfs(int x,int fa,int g,int last_g){
dis_[x].push_back(dis[x]);par[x].push_back(g);
insert1(rt[g],dis[x]-r[x],rt[g],rt[g]);son[g].push_back(x);
if(last_g!=0) insert1(rt_f[g],dis_[x][dis_[x].size()-2]-r[x],rt_f[g],rt_f[g]);
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;if (y==fa||visit[y]) continue;
dis[y]=dis[x]+z;dfs(y,x,g,last_g);
}
}
inline void solve(int x,int last_g){
visit[x]=1;int sum1=sum;dis[x]=0;dfs(x,0,x,last_g);int rot=root;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]) continue;
root=0;if (sz[y]>sz[x]) sum=sum1-sz[x];else sum=sz[y];
get_root(y,x);solve(root,rot);
}//print(rt[x]);printf("%d\n",x);
}
inline void rebuild(int x,int fa){
vector<int> tmp=son[x];int szf=par[fa].size();
for (int i=0;i<tmp.size();++i){
int y=tmp[i];visit[y]=0;
son[y].clear();par[y].resize(szf);dis_[y].resize(szf);
del(rt[y]);del(rt_f[y]);
}sum=tmp.size();root=0;get_root(x,x);solve(root,fa);
}
inline int calc(int x,int fa,int w){
par[x]=par[fa];dis_[x]=dis_[fa];int tmp=0;
dis_[x].push_back(-w);par[x].push_back(x);
for (int i=0;i<dis_[x].size();++i){
dis_[x][i]+=w;son[par[x][i]].push_back(x);
tmp+=qk(rt[par[x][i]],r[x]-dis_[x][i]);if (!i) continue;
tmp-=qk(rt_f[par[x][i]],r[x]-dis_[x][i-1]);
}return tmp;
}
inline void check(int x){
for (int i=0;i<par[x].size();++i){
insert1(rt[par[x][i]],dis_[x][i]-r[x],rt[par[x][i]],rt[par[x][i]]);
if (!i) continue;
insert1(rt_f[par[x][i]],dis_[x][i-1]-r[x],rt_f[par[x][i]],rt_f[par[x][i]]);
}
for (int i=0;i<par[x].size()-1;++i){
int sznow=size[rt[par[x][i]]],szson=size[rt[par[x][i+1]]];
if (sznow<=30) break;
if (szson>sznow*alpha) {rebuild(par[x][i],i==0?0:par[x][i-1]);break;}
}
}
int main(){
//freopen("flower1.in","r",stdin);
int ID=read();
n=read();root=0;f[0]=inf;
for (int i=1;i<=n;++i){
int a=read()^(ans%mod),c=read();r[i]=read();visit[i]=1;
if (i==1){
insert1(rt[1],-r[i],rt[1],rt[1]);dis_[1].push_back(0);par[1].push_back(1);
son[1].push_back(1);puts("0");continue;
}insert_edge(a,i,c);ans+=calc(i,a,c);check(i);printf("%lld\n",ans);
//for (int i=1;i<=4;++i) print(rt[i]),puts("");puts("line1");
//for (int i=1;i<=4;++i) print(rt_f[i]),puts("");puts("line2");
/*for (int i=1;i<=4;++i){
for (int j=0;j<par[i].size();++j) printf("%d ",par[i][j]);puts("");
}
for (int i=1;i<=4;++i){
for (int j=0;j<dis_[i].size();++j) printf("%d ",dis_[i][j]);puts("");
}*/
}
return 0;
}

点分+treap+替罪羊树思想

#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#define N 110000
#define M 4000010
#define mod 1000000000
#define ll long long
#define alpha 0.8
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x*f;
}
inline void print(ll x){
if (!x) {puts("0");return;}int now[70],len=0;
while(x) now[++len]=x%10,x/=10;
for (int i=len;i;--i) putchar(now[i]+'0');puts("");
}
ll ans;bool visit[N];
int h[N],n,num,r[N],dis[N],f[N],root,sum,rt[N],rt_f[N],cnt,sz[N];
int size[M],fa[M],nm[M],c[M][2],v[M],rd[M];
struct node{
int y,z,next;
}data[N<<1];
vector<int>dis_[N],par[N],son[N];queue<int>rec;
inline void insert_edge(int x,int y,int z){
data[++num].y=y;data[num].next=h[x];data[num].z=z;h[x]=num;
data[++num].y=x;data[num].next=h[y];data[num].z=z;h[y]=num;
}
inline int newnode(){
if (rec.empty()) return ++cnt;int x=rec.front();rec.pop();return x;
}
/*inline void print(int x){
if (c[x][0]) print(c[x][0]);
printf("%d %d ",v[x],nm[x]);
if (c[x][1]) print(c[x][1]);
}*/
inline void update(int x){
size[x]=size[c[x][0]]+nm[x]+size[c[x][1]];
}
/*inline void rotate(int x,int &tar){
int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
while(x!=tar){
int y=fa[x],z=fa[y];
if (y!=tar){
if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
}rotate(x,tar);
}
}*/
inline int qk(int x,int vv){
if (!x) return 0;
if(vv<v[x]) return qk(c[x][0],vv);
if (vv==v[x]) return size[c[x][0]]+nm[x];
return size[c[x][0]]+nm[x]+qk(c[x][1],vv);
}
/*inline void insert1(int &x,int vv,int f,int &rot){
if (!x) {x=newnode();fa[x]=f;size[x]=nm[x]=1;v[x]=vv;return;}
if(vv==v[x]) {++nm[x],++size[x];return;}//,splay(x,rot)}splay(x,rot);
if(vv<v[x]) {
insert1(c[x][0],vv,x,rot);update(x);if (size[x]<=30) return;
if(size[c[x][0]]>size[x]*alpha) splay(c[x][0],rot);
}
else {
insert1(c[x][1],vv,x,rot);update(x);if (size[x]<=30) return;
if(size[c[x][1]]>size[x]*alpha) splay(c[x][1],rot);
}
}*/
inline void l_rotate(int &x){
int tmp=c[x][1];c[x][1]=c[tmp][0];c[tmp][0]=x;update(x);update(tmp);x=tmp;
}
inline void r_rotate(int &x){
int tmp=c[x][0];c[x][0]=c[tmp][1];c[tmp][1]=x;update(x);update(tmp);x=tmp;
}
inline void insert1(int &x,int vv){
if (!x) {x=newnode();v[x]=vv;size[x]=nm[x]=1;rd[x]=rand();return;}
if (v[x]==vv) {++size[x],++nm[x];return;}
if (vv<v[x]){
insert1(c[x][0],vv);update(x);if (rd[c[x][0]]<rd[x]) r_rotate(x);
return;
}insert1(c[x][1],vv);update(x);if (rd[c[x][1]]<rd[x]) l_rotate(x);
}
inline void del(int &x){
if (!x) return;
rec.push(x);del(c[x][0]);del(c[x][1]);rd[x]=size[x]=nm[x]=fa[x]=c[x][0]=c[x][1]=v[x]=0;x=0;
}
inline void get_root(int x,int fa){
sz[x]=1;f[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa||visit[y]) continue;
get_root(y,x);sz[x]+=sz[y];f[x]=max(f[x],sz[y]);
}f[x]=max(f[x],sum-sz[x]);
if (f[root]>f[x]) root=x;
}
inline void dfs(int x,int fa,int g,int last_g){
dis_[x].push_back(dis[x]);par[x].push_back(g);
insert1(rt[g],dis[x]-r[x]);son[g].push_back(x);
if(last_g!=0) insert1(rt_f[g],dis_[x][dis_[x].size()-2]-r[x]);
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;if (y==fa||visit[y]) continue;
dis[y]=dis[x]+z;dfs(y,x,g,last_g);
}
}
inline void solve(int x,int last_g){
visit[x]=1;int sum1=sum;dis[x]=0;dfs(x,0,x,last_g);int rot=root;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]) continue;
root=0;if (sz[y]>sz[x]) sum=sum1-sz[x];else sum=sz[y];
get_root(y,x);solve(root,rot);
}//print(rt[x]);printf("%d\n",x);
}
inline void rebuild(int x,int fa){
vector<int> tmp=son[x];int szf=par[fa].size();
for (int i=0;i<tmp.size();++i){
int y=tmp[i];visit[y]=0;
son[y].clear();par[y].resize(szf);dis_[y].resize(szf);
del(rt[y]);del(rt_f[y]);
}sum=tmp.size();root=0;get_root(x,x);solve(root,fa);
}
inline int calc(int x,int fa,int w){
par[x]=par[fa];dis_[x]=dis_[fa];int tmp=0;
dis_[x].push_back(-w);par[x].push_back(x);
for (int i=0;i<dis_[x].size();++i){
dis_[x][i]+=w;son[par[x][i]].push_back(x);
tmp+=qk(rt[par[x][i]],r[x]-dis_[x][i]);if (!i) continue;
tmp-=qk(rt_f[par[x][i]],r[x]-dis_[x][i-1]);
}return tmp;
}
inline void check(int x){
for (int i=0;i<par[x].size();++i){
insert1(rt[par[x][i]],dis_[x][i]-r[x]);
if (!i) continue;
insert1(rt_f[par[x][i]],dis_[x][i-1]-r[x]);
}
for (int i=0;i<par[x].size()-1;++i){
int sznow=size[rt[par[x][i]]],szson=size[rt[par[x][i+1]]];
if (sznow<=30) break;
if (szson>sznow*alpha) {rebuild(par[x][i],i==0?0:par[x][i-1]);break;}
}
}
int main(){
//freopen("flower1.in","r",stdin);
int ID=read();srand(998244353);
n=read();root=0;f[0]=inf;
for (int i=1;i<=n;++i){
int a=read()^(ans%mod),c=read();r[i]=read();visit[i]=1;
if (i==1){
insert1(rt[1],-r[i]);dis_[1].push_back(0);par[1].push_back(1);
son[1].push_back(1);puts("0");continue;
}insert_edge(a,i,c);ans+=calc(i,a,c);check(i);print(ans);//printf("%lld\n",ans);
//for (int i=1;i<=4;++i) print(rt[i]),puts("");puts("line1");
//for (int i=1;i<=4;++i) print(rt_f[i]),puts("");puts("line2");
/*for (int i=1;i<=4;++i){
for (int j=0;j<par[i].size();++j) printf("%d ",par[i][j]);puts("");
}
for (int i=1;i<=4;++i){
for (int j=0;j<dis_[i].size();++j) printf("%d ",dis_[i][j]);puts("");
}*/
}
return 0;
}