zoukankan      html  css  js  c++  java
  • BZOJ 4539: [Hnoi2016]树 [主席树 lca]

    4539: [Hnoi2016]树

    题意:不想写。复制模板树的子树,查询两点间距离。


    终于有一道会做的题了......

    画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在大点的lca里

    然后每个大点维护一坨信息:节点编号的区间范围,到根的距离,大点对应子树的根,大点是接在了模板树里哪个点下面

    然后做就行了

    给出大树上一个点的编号,找到对应的大点可以二分;再找到对应模板树上的点,因为编号是按原大小来的,就是子树k大值,可以用主席树

    求距离的时候我分了三种情况:

    1. 同一个大点
    2. 大点在一条链上
    3. 普通情况

    第一次写这么长的代码...(以前我压行是有多厉害)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define fir first
    #define sec second
    #define lc(x) t[x].l
    #define rc(x) t[x].r
    typedef long long ll;
    const int N=2e5+5;
    inline ll read() {
        char c=getchar(); ll x=0,f=1;
        while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
        while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    int n, m, Q; ll x, y;
    
    namespace temT {
    	struct edge{int v, ne;} e[N<<1];
    	int cnt=1, h[N];
    	inline void ins(int u, int v) {
    		e[++cnt] = (edge){v, h[u]}; h[u] = cnt;
    		e[++cnt] = (edge){u, h[v]}; h[v] = cnt;
    	}
    	int deep[N], size[N], fa[N][18];
    	pair<int, int> dfn[N]; int dfc, ver[N];
    	void dfs(int u) {
    		for(int i=1; (1<<i) <= deep[u]; i++) 
    			fa[u][i] = fa[ fa[u][i-1] ][i-1];
    
    		dfn[u].fir = ++dfc; ver[dfc] = u;
    		size[u] = 1;
    		for(int i=h[u];i;i=e[i].ne) 
    			if(e[i].v != fa[u][0]) {
    				fa[e[i].v][0] = u;
    				deep[e[i].v] = deep[u]+1;
    				dfs(e[i].v);
    				size[u] += size[e[i].v];
    			}
    		dfn[u].sec = dfc;
    	}
    	inline int lca(int x, int y) {
    		if(deep[x] < deep[y]) swap(x, y);
    		int bin = deep[x] - deep[y];
    		for(int i=16; i>=0; i--) if((1<<i) & bin) x = fa[x][i];
    		if(x == y) return x;
    		for(int i=16; i>=0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    		return fa[x][0];
    	}
    	inline int dis(int x, int y) {return abs(deep[x] - deep[y]);}
    
    	struct meow{int l, r, size;} t[N*20];
    	int sz, root[N];
    	void insert(int &x, int l, int r, int p) {
    		t[++sz] = t[x]; x = sz;
    		t[x].size++;
    		if(l==r) return;
    		int mid = (l+r)>>1;
    		if(p <= mid) insert(t[x].l, l, mid, p);
    		else insert(t[x].r, mid+1, r, p);
    	}
    	int kth(int id, int k) {
    		int x = root[ dfn[id].fir - 1 ], y = root[ dfn[id].sec ], l=1, r=n;
    		//printf("kth %d    %d %d  %d
    ", id, x, y, k);
    		while(l != r) {
    			int mid = (l+r)>>1, lsize = t[lc(y)].size - t[lc(x)].size;
    			if(k <= lsize) x = lc(x), y = lc(y), r = mid;
    			else k -= lsize, x = rc(x), y = rc(y), l = mid+1;
    		}
    		return l;
    	}
    
    	void build() {
    		dfs(1);
    		for(int i=1; i<=dfc; i++) root[i]=root[i-1], insert(root[i], 1, n, ver[i]);
    	}
    }
    
    namespace bigT {
    	struct edge{int v, ne;} e[N];
    	int cnt=1, h[N];
    	inline void ins(int u, int v) {
    		e[++cnt] = (edge){v, h[u]};
    	}
    	int fa[N][17], deep[N];
    	inline void update(int u) {
    		for(int i=1; (1<<i) <= deep[u]; i++) 
    			fa[u][i] = fa[ fa[u][i-1] ][i-1];
    	}
    	inline int lca(int x, int y) {
    		if(deep[x] < deep[y]) swap(x, y);
    		int bin = deep[x] - deep[y];
    		for(int i=16; i>=0; i--) if((1<<i) & bin) x = fa[x][i];
    		if(x == y) return x;
    		for(int i=16; i>=0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    		return fa[x][0];
    	}
    
    	struct info{
    		ll l, r, dis, root, in;
    		//void print() {printf("[%d, %d]  %d  %d %d
    ", l, r, dis, root, in);}
    	} li[N];
    	int tot; ll size;
    	void init() { 
    		tot=1; size=n; 
    		li[1] = (info){1, n, 0, 1, 0}; 
    	}
    	inline int find(ll x) {
    		int l=1, r=tot;
    		while(l <= r) {
    			int mid = (l+r)>>1;
    			if(li[mid].l <= x && x <= li[mid].r) return mid;
    			else if(x < li[mid].l) r = mid-1;
    			else l = mid+1;
    		}
    		return -1;
    	}
    	
    	void move(ll x, ll y) { //printf("
    move %d --> %d
    ", x, y);
    		int by = find(y); 
    		y = temT::kth(li[by].root, y - li[by].l + 1);  //printf("by %d  %d
    ", by, y);
    		int bx = ++tot;
    		li[bx] = (info){size+1, size + temT::size[x], li[by].dis + temT::dis(y, li[by].root) + 1, x, y};
    		size = li[bx].r;
    		fa[bx][0] = by;
    		deep[bx] = deep[by]+1;
    		update(bx);
    	}
    
    	void quer(ll x, ll y) { //printf("
    quer %d --- %d
    ", x, y);
    		int bx = find(x); x = temT::kth(li[bx].root, x - li[bx].l + 1); //printf("bx %d  %d
    ", bx, x);
    		int by = find(y); y = temT::kth(li[by].root, y - li[by].l + 1); //printf("by %d  %d
    ", by, y);
    
    		ll ans=0;
    		if(bx == by) {
    			int p = temT::lca(x, y);
    			ans = temT::dis(x, p) + temT::dis(y, p);
    		} else {
    			int bp = lca(bx, by); //printf("bp %d
    ", bp);
    			if(bp == by) swap(bx, by), swap(x, y);
    			if(bp == bx) { 
    				ans += li[by].dis - li[bx].dis + temT::dis(y, li[by].root) + temT::dis(x, li[bx].root);
    				//printf("ans %d
    ", ans);
    				//for(int i=16; i>=0; i--) printf("fa %d %d %d  %d
    ", by, i, fa[by][i], deep[fa[by][i]]);
    				for(int i=16; i>=0; i--) 
    					if(fa[by][i] && deep[ fa[by][i] ] > deep[bx]) by = fa[by][i];
    				y = li[by].in;
    				//printf("iny %d  %d
    ", by, y);
    				int p = temT::lca(x, y);
    				if(p != li[bx].root) ans += temT::dis(x, p) + temT::dis(y, p) - temT::dis(x, li[bx].root) - temT::dis(y, li[bx].root);
    			} else {
    				ans = li[bx].dis + li[by].dis - (li[bp].dis << 1); //printf("ans %d  %d %d %d
    ", ans, li[bx].dis, li[by].dis, li[bp].dis);
    				ans += temT::dis(x, li[bx].root) + temT::dis(y, li[by].root); //printf("ans %d
    ", ans);
    
    				for(int i=16; i>=0; i--) {
    					if(fa[bx][i] && deep[ fa[bx][i] ] > deep[bp]) bx = fa[bx][i];
    					if(fa[by][i] && deep[ fa[by][i] ] > deep[bp]) by = fa[by][i];
    				}
    				x = li[bx].in, y = li[by].in; //printf("in %d  %d    %d  %d
    ", bx, x, by, y);
    				int p = temT::lca(x, y);
    				if(p != li[bp].root) 
    					ans += temT::dis(x, p) + temT::dis(y, p) - temT::dis(x, li[bp].root) - temT::dis(y, li[bp].root);
    			}
    		}
    		printf("%lld
    ", ans);
    	}
    }
    
    int main() {
    	//freopen("in", "r", stdin);
    	freopen("tree_tenderRun.in", "r", stdin);
    	freopen("tree_tenderRun.out", "w", stdout);
    	n=read(); m=read(); Q=read();
    	for(int i=1; i<n; i++) temT::ins(read(), read());
    	temT::build();
    	bigT::init(); 
    	for(int i=1; i<=m; i++) x=read(), y=read(), bigT::move(x, y); 
    	for(int i=1; i<=Q; i++) x=read(), y=read(), bigT::quer(x, y);
    }
    
    
  • 相关阅读:
    2018.11.21 struts2获得servletAPI方式及如何获得参数
    2018.11.20 Struts2中对结果处理方式分析&struts2内置的方式底层源码剖析
    2018.11.19 Struts2中Action类的书写方式
    2018.11.18 Sturts2配置详解&常量配置进阶
    2018.11.17 Struts2框架入门
    需求分析
    可行性研究
    防火墙
    homework1
    静态网页开发技术
  • 原文地址:https://www.cnblogs.com/candy99/p/6694861.html
Copyright © 2011-2022 走看看