WC2014-紫荆花之恋
2017-05-04 22:19
369 查看
一棵树,每条边有边权,点有点权\(r\),\(n\)次加入一个点,给出它与父亲的连边长度和它的点权,问此时总共有多少对点满足\(r_i+r_j\ge dist(i,j)\)。\(n\le 10^5\)。
但这样明显会重复计算从同一个子树来的点,所以在每个点还要再开一个平衡树,记录一下子树中到这个点的父亲的值,减一下即可。
上面我们说直接把这个点挂在下面,这事实上是很不对的,一个链的情况就可以把这个卡掉。于是我们可以利用重构的思想,如果一个子树的大小大于它父亲子树大小的\(\alpha\),那么就找到最上面一个这样的位置,重构整颗子树,把它变成一个点分治树的样子。替罪羊树的时间复杂度分析说明这样做的复杂度为\(O(f(n)log _{\frac{1}{\alpha}}n)\),其中\(f(n)\)为重构大小为\(n\)的子树的复杂度。
这一题中,点分治树的深度是\(O(logn)\)的,所以一次重构的可以直接每个点往上跳\(O(logn)\)个父亲,每次直接向平衡树中插入,总复杂度为\(O(nlog^3n)\)。
不过学到了一种点分治找中心的神奇写法,超级好写,只要两行~
分析
树上点对统计可以使用点分治。每次只需要统计新增了多少对满足条件的点。设一对点\((u,v)\)的lca为\(k\),那么条件可以转化为\(r_u-dist(u,k)\ge dist(v,k)-r_v\),每次新加入点直接挂在父亲下面并直接往上跳,设当前跳到点\(c\),只要统计经过这个点有多少满足条件的即可。我们拿着\(r_u-dist(u,k)\)去查询有多少个\(dist(v,k)-r_v\)小于等于它就好了。用平衡树来维护这个东西,查询完之后就把它插入平衡树里。但这样明显会重复计算从同一个子树来的点,所以在每个点还要再开一个平衡树,记录一下子树中到这个点的父亲的值,减一下即可。
上面我们说直接把这个点挂在下面,这事实上是很不对的,一个链的情况就可以把这个卡掉。于是我们可以利用重构的思想,如果一个子树的大小大于它父亲子树大小的\(\alpha\),那么就找到最上面一个这样的位置,重构整颗子树,把它变成一个点分治树的样子。替罪羊树的时间复杂度分析说明这样做的复杂度为\(O(f(n)log _{\frac{1}{\alpha}}n)\),其中\(f(n)\)为重构大小为\(n\)的子树的复杂度。
这一题中,点分治树的深度是\(O(logn)\)的,所以一次重构的可以直接每个点往上跳\(O(logn)\)个父亲,每次直接向平衡树中插入,总复杂度为\(O(nlog^3n)\)。
代码
弃坑啦!!!!写过splay,treap,奇怪重量平衡树,最后改成替罪羊树来作平衡树,现在uoj上80分。不过学到了一种点分治找中心的神奇写法,超级好写,只要两行~
#include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<algorithm> using namespace std; typedef long long giant; int read() { int x=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } void write(giant x) { if (!x) puts("0"); else { static char s[25]; int tot=0; while (x) s[++tot]=x%10+'0',x/=10; while (tot) putchar(s[tot--]); puts(""); } } const int maxn=1e5+1; const int maxm=5e6; const int maxj=17; const double alpha=0.77; giant ans=0; int fa[maxn],d[maxn],rec[maxn],size[maxn],my[maxn],onf[maxn],n; bool able[maxn]; vector<int> g[maxn]; inline int conv(int x) { return x^((int)(ans%(giant)1e9)); } struct graph { int h[maxn],tot,f[maxn][maxj],dep[maxn],dis[maxn]; graph ():tot(0) { for (int i=0;i<maxj;++i) f[1][i]=1; } void add(int u,int v,int w) { g[u].push_back(v); g[v].push_back(u); f[v][0]=u; for (int j=1;j<maxj;++j) f[v][j]=f[f[v][j-1]][j-1]; dep[v]=dep[u]+1,dis[v]=dis[u]+w; } int lca(int x,int y) { if (dep[x]<dep[y]) swap(x,y); for (int j=maxj-1;j>=0;--j) if (dep[f[x][j]]>=dep[y]) x=f[x][j]; if (x==y) return x; for (int j=maxj-1;j>=0;--j) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j]; return f[x][0]; } int dist(int x,int y) { return dis[x]+dis[y]-2*dis[lca(x,y)]; } } G; int aux[maxn]; struct Treap { struct node { int ch[2],fa,val,size; } t[maxm]; int pool[maxm],per; Treap ():per(0) { for (int i=1;i<maxm;++i) pool[i]=i; } inline void update(int x) { t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1; } inline void delnode(int &x) { if (!x) return; t[x].ch[0]=t[x].ch[1]=t[x].fa=t[x].val=t[x].size=0; pool[per--]=x; x=0; } inline int newnode(int x) { int nw=pool[++per]; t[nw].size=1; t[nw].val=x; return nw; } bool rson(int x) { return t[t[x].fa].ch[1]==x; } void travel(int x,int &len) { if (!x) return; travel(t[x].ch[0],len); aux[++len]=t[x].val; travel(t[x].ch[1],len); delnode(x); } int reb(int l,int r) { if (l>r) return 0; int mid=l+r>>1; int nw=newnode(aux[mid]); t[nw].ch[0]=reb(l,mid-1); t[nw].ch[1]=reb(mid+1,r); update(nw); return nw; } void rebid(int x) { int len=0; travel(x,len); int fat=t[x].fa; bool d=rson(x); int l=1,r=len; t[fat].ch[d]=reb(l,r); update(fat); } inline void insert(int &rt,int x) { int nw=newnode(x); if (!rt) { rt=nw; return; } int now=rt; while (true) { ++t[now].size; int &tmp=t[now].ch[x>t[now].val]; if (tmp) now=tmp; else { tmp=nw; break; } } int goat=0; for (;t[now].fa;now=t[now].fa) if (t[now].size>0.6*t[t[now].fa].size) goat=now; if (goat) rebid(goat); } inline int le(int now,int x) { int ret=0; while (now) { if (x>t[now].val) ret+=t[t[now].ch[0]].size+1; else if (x==t[now].val) ++ret; now=t[now].ch[x>t[now].val]; } return ret; } void clear(int &x) { if (x) clear(t[x].ch[0]),clear(t[x].ch[1]); delnode(x); } } tree; inline void addit(int u,int v,int w) { G.add(u,v,w); fa[v]=u,d[v]=d[u]+1,size[v]=1; } inline bool bad(int x) { return size[x]>alpha*size[fa[x]]; } void label(int x,int f,int no) { able[x]=true; for (int v:g[x]) if (v!=f && d[v]>d[no]) label(v,x,no); } int Size(int x,int f) { size[x]=1; for (int v:g[x]) if (v!=f && able[v]) size[x]+=Size(v,x); return size[x]; } int Root(int x,int f,int hf) { for (int v:g[x]) if (v!=f && able[v] && size[v]>hf) return Root(v,x,hf); return x; } void rebuild(int x,int fat,int up) { int sz=Size(x,0),rt=Root(x,0,sz>>1); able[rt]=false,d[rt]=d[fa[rt]=fat]+1,size[rt]=size[x]; tree.clear(my[rt]),tree.clear(onf[rt]); for (int v:g[rt]) if (able[v]) rebuild(v,rt,up); for (int y=rt;y!=up;y=fa[y]) { tree.insert(my[y],G.dist(y,rt)-rec[rt]); if (!fa[y]) break; tree.insert(onf[y],G.dist(fa[y],rt)-rec[rt]); } } int cs=0; inline void work(int x) { int goat=0; for (int y=x;y;y=fa[y]) { int d=G.dist(x,y); ans+=tree.le(my[y],rec[x]-d); tree.insert(my[y],d-rec[x]); if (!fa[y]) break; d=G.dist(x,fa[y]); ans-=tree.le(onf[y],rec[x]-d); tree.insert(onf[y],d-rec[x]); ++size[fa[y]]; if (bad(y)) goat=y; } if (goat) ++cs,label(fa[goat],0,fa[fa[goat]]),rebuild(fa[goat],fa[fa[goat]],fa[fa[goat]]); } int main() { #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("my.out","w",stdout); #endif srand(200); puts("0"); read(),n=read(),read(),read(),rec[1]=read(); tree.insert(my[1],-rec[1]),size[1]=1; for (int i=2;i<=n;++i) { // int x=conv(read()); int x=read(); int c=read(); rec[i]=read(); addit(x,i,c); work(i); write(ans); } return 0; }
相关文章推荐
- bzoj3435 [Wc2014]紫荆花之恋
- bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400
- 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT
- BZOJ 3435: [Wc2014]紫荆花之恋
- BZOJ 3435 Wc2014 紫荆花之恋 动态树分治+替罪羊树+Treap
- [BZOJ3435][Wc2014]紫荆花之恋-替罪羊树-treap-动态点分治
- wc2014 紫荆花之恋
- UOJ#55 [WC2014]紫荆花之恋
- NKOJ 2703 (WC 2014)紫荆花之恋 (点分治+平衡树+替罪羊)
- 【WC2014】紫荆花之恋
- bzoj3435 [Wc2014]紫荆花之恋
- Wc2014 紫荆花之恋
- bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)
- [替罪羊树 动态点分治 替罪羊式重构] BZOJ 3435 [Wc2014]紫荆花之恋 & UOJ #55 【WC2014】紫荆花之恋
- Wc2014 紫荆花之恋
- [WC 2014]紫荆花之恋
- BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋
- BZOJ3435: [Wc2014]紫荆花之恋 动态树分治 替罪羊树
- 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋
- 【BZOJ3435】【UOJ55】【WC2014】紫荆花之恋