zoukankan      html  css  js  c++  java
  • WC2014-紫荆花之恋

    一棵树,每条边有边权,点有点权(r)(n)次加入一个点,给出它与父亲的连边长度和它的点权,问此时总共有多少对点满足(r_i+r_jge dist(i,j))(nle 10^5)

    分析

    树上点对统计可以使用点分治。每次只需要统计新增了多少对满足条件的点。设一对点((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;
    }
    
  • 相关阅读:
    不容易系列之一(错排)
    找新朋友(欧拉函数)
    二分查找
    快速排序(分治)
    归并排序(分治)
    畅通工程(并查集)
    A Knight's Journey (DFS)
    Network Saboteur (DFS)
    Oil Deposits(油田)(DFS)
    Dungeon Master (三维BFS)
  • 原文地址:https://www.cnblogs.com/owenyu/p/6810224.html
Copyright © 2011-2022 走看看