您的位置:首页 > 其它

[WC2014]紫荆花之恋

2018-03-10 22:09 260 查看
题意:每次插入一个点,询问dis(i,j)≤ri+rjdis(i,j)≤ri+rj的数量

①:假装这棵树是一开始给你的

树上路径问题−>−>点分治

考虑重心uu,答案就是dis(i,u)+dis(u,j)≤ri+rjdis(i,u)+dis(u,j)≤ri+rj的数量

移一个项⇒dis(i,u)−ri≤rj−dis(u,j)⇒dis(i,u)−ri≤rj−dis(u,j)

把所有的dis(i,u)−ridis(i,u)−ri插入uu的平衡树,询问uu的平衡树中rj−dis(u,j)rj−dis(u,j)的排名就好了

计算贡献什么的基本都是点分治的基本套路(其实主要是这部分大家都讲得很清楚了)

②:这棵树会动怎么做?

考虑用按照替罪羊树的思想,从这个点不断跳上一层重心,当满足Szi>Szfai∗αSzi>Szfai∗α时就重构faifai这棵树,当然faifai要是最浅的

③:细节&卡常

听起来似乎好简单(想完题解后我也是这么想的),但是写起来写到怀疑人生

我们讲一讲这道题最要命的地方——细节&卡常

1.1.你需要一颗高效的平衡树,可能你80−9080−90分,这时候换一颗平衡树说不定就卡过了;如果你用TreapTreap的话不如手写随机会快一些

2.2.你需要一个平衡树的垃圾桶,因为这题重构是要清空这棵树以及这棵树上每个节点的平衡树的,这里会造成巨大的空间浪费(其实你不写垃圾桶你可能会被卡到MLEMLE)

3.3.我稍微感受了一下平衡树写法的速度大概是这样的:结构体>>指针>>数组

其实想想也比较好理解吧

4.4.对于像我一样的手残党,一开始写代码的时候最好还是写到namespacenamespace里面吧,之前因为平衡树节点的sizesize用szsz当名字,然后点分治按照习惯也写的szsz,后来发现重名了,然后就稍微改了一下,然后有一个地方没有改,但是他小数据跑出来了exm?!?!exm?!?!,然后调到绝望才找出来.什么你说那样不好看??你不知道先写完保证不错然后ctrl+Fctrl+F替换吗?

5.5.什么你问我为什么第一名那么快??其实主要是处理链的部分非常快

因为我们可以发现链完全不要像上面那么做

假设11是链的顶端,左右分别拉一条链,令di=dis(1,i)di=dis(1,i)

考虑新加进来的点一定在链的底端,考虑两种情况

du−di≤ru+ri⇒−di−ri≤ru−du,udu−di≤ru+ri⇒−di−ri≤ru−du,u和ii在同一边

du+di≤ru+ri⇒di−ri≤ru−du,udu+di≤ru+ri⇒di−ri≤ru−du,u和ii在不同边

所以你维护44棵平衡树就可以在O(nlogn)O(nlog⁡n)的时间内处理出答案了

注意要特判当du≤r1+rudu≤r1+ru时答案要减11

6.6.卡常有风险,codecode需谨慎

7.7.什么你说还不够快??那你可以用bfsbfs来求重心,不要用STLSTL,能放在一块的用结构体存起……

至于代码的话将就着看吧

#include<bits/stdc++.h>
#define fp(i,a,b) for(int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(int i=a,I=b-1;i>I;--i)
#define go(i,u) for(int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1<<17,L=30,M=35*N,P=1e9;
const double alpha=0.777,beta=0.77;
typedef int arr
;
typedef long long ll;
struct eg{int nx,to,w;}e[2*N];
int n,ce;arr R,fi;ll ans;
inline void add(int u,int v,int w){e[++ce]=eg{fi[u],v,w},fi[u]=ce;}
//Scapegoat Tree
struct sgt{int sz,w,c[2];}tr[M];int cn,cb,bin[M];
inline int New(){return cb?bin[cb--]:++cn;}
inline void up(int u){tr[u].sz=tr[tr[u].c[0]].sz+tr[tr[u].c[1]].sz+1;}
inline void rot(int&u,int k){int v=tr[u].c[k];tr[u].c[k]=tr[v].c[!k],tr[v].c[!k]=u,up(u),up(u=v);}
void ins(int&u,int w){
if(!u)return tr[u=New()]=sgt{1,w,{0,0}},void();
bool k=w>tr[u].w;++tr[u].sz;ins(tr[u].c[k],w);if(tr[tr[u].c[k]].sz>tr[u].sz*beta)rot(u,k);
}
inline int rk(int u,int w){if(!u)return 0;return w<tr[u].w?rk(tr[u].c[0],w):(tr[tr[u].c[0]].sz+1+rk(tr[u].c[1],w));}
void cle(int&u){if(!u)return;bin[++cb]=u;cle(tr[u].c[0]);cle(tr[u].c[1]);u=0;}
//Dynamic Divide
struct dyd{int d,f[L],l[L];}g
;
int rt,Sum,T
[2];arr q,d,Sz,Fa,fx;bool vis
;vector<int>Tr
;
void gr(int u,int fa){
fx[u]=0,Sz[u]=1;
go(i,u)if(!vis[v]&&v^fa)gr(v,u),Sz[u]+=Sz[v],cmax(fx[u],Sz[v]);
cmax(fx[u],Sum-Sz[u]);if(fx[u]<fx[rt])rt=u;
}
inline void bfs(int u){
int h=1,t=1;q[t]=u;
while(h<=t){vis[u=q[h++]]=1;go(i,u)if(!vis[v])d[q[++t]=v]=d[u]+e[i].w;}
q[0]=t;fp(i,1,t)vis[q[i]]=0;
}
inline void pb(int u,int f,int w){dyd&d=g[u];d.f[d.d]=f,d.l[d.d]=w,++d.d;}
void sol(int u){
vis[u]=1;ins(T[u][0],-R[u]);Tr[u].push_back(u),pb(u,u,0);
go(i,u)if(!vis[v]){
d[v]=e[i].w,bfs(v),Sum=Sz[v],gr(v,rt=0);
fp(j,1,q[0])Tr[u].push_back(v=q[j]),ins(T[u][0],d[v]-R[v]),ins(T[rt][1],d[v]-R[v]),pb(v,u,d[v]);
Fa[rt]=u,sol(rt);
}
}
inline void Re(int u){
int*a=Tr[u].data(),NewSiz=g[Fa[u]].d,v;
fp(i,1,Tr[u].size()-1){
vis[v=a[i]]=0,Tr[v].clear();
cle(T[v][0]),cle(T[v][1]);
g[v].d=NewSiz;
}
Sum=Tr[u].size(),gr(u,rt=vis[u]=0);
T[rt][1]=T[u][1];cle(T[u][0]);T[u][1]=0;
Tr[u].clear();g[u].d=NewSiz;Fa[rt]=Fa[u];sol(rt);
}
inline void calc(int u,int f,int w){
add(u,f,w),add(f,u,w),Fa[u]=f;g[u]=g[f];
vis[u]=1;pb(u,u,-w);int*a=g[u].f,*b=g[u].l,p;
fp(i,0,g[u].d-1){
b[i]+=w;Tr[p=a[i]].push_back(u);
ans+=rk(T[p][0],R[u]-b[i])-(i?rk(T[p][1],R[u]-b[i-1]):0);
ins(T[p][0],b[i]-R[u]);if(i)ins(T[p][1],b[i-1]-R[u]);
}we(ans);
fp(i,1,g[u].d-1)if(tr[T[a[i]][0]].sz>tr[T[a[i-1]][0]].sz*alpha)return Re(a[i-1]);
}
int a,b,wic,t[2][2],Chain[2]={1,1};
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(n);int u=2;fx[0]=N,we(0);
sd(a),sd(b),sd(R[1]);fp(i,0,1)fp(j,0,1)ins(t[i][j],-R[1]);
for(;u<=n;++u){
sd(a),sd(b),sd(R[u]);
#ifdef ONLINE_JUDGE
a^=ans%P;
#endif
if(a^Chain[0]&&a^Chain[1])break;
Fa[u]=a;add(u,a,b),add(a,u,b);
wic=Fa[u]==Chain[1],Chain[wic]=u;d[u]=d[a]+b;
ans+=rk(t[0][wic],R[u]-d[u])+rk(t[1][!wic],R[u]-d[u]);
ins(t[0][wic],-d[u]-R[u]);ins(t[1][wic],d[u]-R[u]);
if(d[u]<=R[1]+R[u])--ans;we(ans);
}if(u<=n){
fp(i,0,1)fp(j,0,1)cle(t[i][j]);
Sum=u-1;gr(1,0);Fa[rt]=0;sol(rt);calc(u,a,b);
for(++u;u<=n;++u){
sd(a),sd(b),sd(R[u]);
#ifdef ONLINE_JUDGE
a^=ans%P;
#endif
calc(u,a,b);
}
}
return Ot(),0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: