题目分析:
似乎做过几道点分树的题之后题解还是比较好懂的。
这位dalao的题目分析非常的到位,Orz。
PoPoQQQ的具体解读也非常的清晰,Orz。
Ri+Rj>=dist(i,j)→Ri−dist(i,k)>=dist(k,j)−Rj,k是i,j路径上的一点。
那么就点分治,每个重心上一棵平衡树tree1保存子树内的点j到它的distGj−Rj
儿子上再挂一棵平衡树tree2存儿子对父亲的贡献distfa j−Rj
插入的时候往上查询<=Ri-dist的数就好了。
由于是动态加点,所以不平衡就重构点分树。
重构一次的时间,由于每个点都是暴力插入平衡树,所以是nlog2n的
期望重构logn次,总复杂度按道理来说应该是nlog3n。不知道为什么很多dalao都说是nlog2n
指针操作的有旋Treap真是上天。。%PoPoQQQ。
然后我就怀抱着激动的心情开始打抄代码。。
然后就到了半夜两点钟疯狂TLE。。
然后第二天早上起来一看发现是傻逼错误。。(详见代码注释)
敲完紫荆花之恋感觉整个人虚脱至死神清气爽。。
Code:
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<vector>
#include<algorithm>
#define maxn 100005
#define alpha 0.85
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
inline int Rnd(){
static int G = 3;
return G=G*3ll%998244353;
}
int n,r[maxn];
long long ans;
struct Treap{
static vector<Treap*>bin;
Treap *ch[2];
int val,rnd, cnt,siz;
void* operator new (size_t,int v){//重载指针操作符真是高级操作。。
Treap *ret;
if(!bin.empty()) ret=bin.back(),bin.pop_back();
else{//这个动态申请内存似乎和fread差不多
static Treap *mempool=0,*C=0;
if(C==mempool) mempool=(C=new Treap[1<<15])+(1<<15);
ret=C++;
}
ret->ch[0]=ret->ch[1]=0;//记得清空~
ret->val=v, ret->rnd=Rnd();
ret->cnt=ret->siz=1;
return ret;
}
void operator delete (void *p){
bin.push_back((Treap*)p);
}
friend void Delete(Treap *&x){
if(!x) return;
Delete(x->ch[0]),Delete(x->ch[1]);
delete x; x=0;
}
void upd(){
siz=cnt;//下面访问空指针会RE
if(ch[0]) siz+=ch[0]->siz;
if(ch[1]) siz+=ch[1]->siz;
}
friend void rot(Treap *&x,bool c){
Treap *y=x->ch[c];
x->ch[c]=y->ch[!c], y->ch[!c]=x;
x->upd(), y->upd(), x=y;
}
friend void insert(Treap *&x,int v){
if(!x) {x=new(v)Treap;return;}
if(x->val==v) x->cnt++;
else{
bool c=v>x->val;
insert(x->ch[c],v);
if(x->ch[c]->rnd < x->rnd) rot(x,c);
}
x->upd();//插入完要update!!
}
friend int query(Treap *x,int v){
if(!x) return 0;
if(v<x->val) return query(x->ch[0],v);
return (x->ch[0]?x->ch[0]->siz:0)+x->cnt+query(x->ch[1],v);
}
};
vector<Treap*>Treap::bin;//???
int fir[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],tot;
inline void line(int x,int y,int z){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;w[tot]=z;}
int f[maxn][18],dep[maxn],dis[maxn];
int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=0,k=dep[u]-dep[v];i<=16;i++) if(k&1<<i) u=f[u][i];
if(u==v) return u;
for(int i=16;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
inline int Distance(int u,int v){
return dis[u]+dis[v]-2*dis[LCA(u,v)];
}
namespace Dynamic_TDC{//动态树分治(Divide and Conquer)
int fa[maxn],idx,vis[maxn];
Treap *tree1[maxn],*tree2[maxn];
int del(int x,int pre){
int s=1;
Delete(tree1[x]);
for(int i=fir[x];i;i=nxt[i])
if(vis[to[i]]!=idx&&to[i]!=pre) Delete(tree2[to[i]]),s+=del(to[i],x);
return s;
}
int dfs(int x,int pre,int d,Treap *&p){
int s=1;
insert(p,d-r[x]);
for(int i=fir[x];i;i=nxt[i])
if(vis[to[i]]!=idx&&to[i]!=pre) s+=dfs(to[i],x,d+w[i],p);
return s;
}
int getroot(int x,int pre,int tsz,int &G){
int s=1,flg=1;
for(int i=fir[x];i;i=nxt[i]) if(vis[to[i]]!=idx&&to[i]!=pre){
int tmp=getroot(to[i],x,tsz,G);
if((tmp<<1)>tsz) flg=0;
s+=tmp;
}
if(((tsz-s)<<1)>tsz) flg=0;
if(flg) G=x;
return s;
}
int Tree_Divide_And_Conquer(int x,int tsz){
getroot(x,0,tsz,x);
vis[x]=idx;
dfs(x,0,0,tree1[x]);
for(int i=fir[x];i;i=nxt[i]) if(vis[to[i]]!=idx){
Treap *p=0;
int ss=dfs(to[i],x,w[i],p);
int tmp=Tree_Divide_And_Conquer(to[i],ss);
fa[tmp]=x,tree2[tmp]=p;
}
return x;
}
void rebuild(int x){
int y=fa[x]; ++idx;
for(int i=fa[x];i;i=fa[i]) vis[i]=idx;//子树内的节点可能与上面的fa有连边
Treap *p=tree2[x]; tree2[x]=0;//保留tree2
x=Tree_Divide_And_Conquer(x,del(x,0));
fa[x]=y, tree2[x]=p;
}
void Insert(int x){
for(int i=x,last=0,dist;i;i=fa[i]){
if(fa[i]){
dist=Distance(x,fa[i]);
ans+=query(tree1[fa[i]],r[x]-dist);
ans-=query(tree2[i],r[x]-dist);
insert(tree2[i],dist-r[x]);
}
insert(tree1[i],last-r[x]),last=dist;
}
//check_rebuild
int rep = 0;
for(int i=x;fa[i];i=fa[i])
if(tree1[fa[i]]->siz * alpha <= tree1[i]->siz) rep=fa[i];
if(rep) rebuild(rep);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("H.in","r",stdin);
#endif
scanf("%*d%d",&n);
for(int i=1,x,y;i<=n;i++){
read(x),read(y),read(r[i]),x^=ans%1000000000;
if(x) line(x,i,y),line(i,x,y);
f[i][0]=x,dep[i]=dep[x]+1,dis[i]=dis[x]+y;
for(int j=1;j<=16;j++) f[i][j]=f[f[i][j-1]][j-1];
Dynamic_TDC::fa[i]=x;
Dynamic_TDC::Insert(i);
printf("%lld\n",ans);
}
}