• BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)


    BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度).

    两种做法

    1 树剖+离线+线段树

    这道题求的是一个点zz[l,r][l,r]内所有点的lcalca的深度之和.可以发现,dep[lca(u,v)]dep[lca(u,v)]就等于uu到根vv到根的路径的交集路径的长度.那么只要把[l,r][l,r]所有点到根的路径标记了,然后用zz点往根跑统计答案就行了.这样的话差分一下,离线就可以处理了.

    时间复杂度O(nlog2n)O(nlog^2n)

    CODE

    #include <vector>
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    
    inline void read(int &num) {
    	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
    	for(num=0; isdigit(ch); num=num*10+ch-'0',ch=getchar()); num*=flg;
    }
    const int MAXN = 50005;
    const int mod = 201314;
    
    int n, tot, Q, dfn[MAXN], seq[MAXN], tmr, fir[MAXN], cnt;
    struct edge { int to, nxt; }e[MAXN];
    
    inline void add(int u, int v) {
    	e[cnt] = (edge){ v, fir[u] }, fir[u] = cnt++;
    }
    int dep[MAXN], fa[MAXN], sz[MAXN], top[MAXN], son[MAXN];
    void dfs(int u) {
    	dep[u] = dep[fa[u]] + (sz[u]=1);
    	for(int v, i = fir[u]; ~i; i = e[i].nxt) {
    		dfs(v=e[i].to), sz[u] += sz[v];
    		if(sz[v] > sz[son[u]]) son[u] = v;
    	}
    }
    void dfs2(int u, int tp) {
    	top[u] = tp; dfn[u] = ++tmr;
    	if(son[u]) dfs2(son[u], tp);
    	for(int v, i = fir[u]; ~i; i = e[i].nxt)
    		if((v=e[i].to) != son[u]) dfs2(v, v);
    }
    
    struct node {
    	int tim, x, id, flg;
    }q[MAXN<<1];
    inline bool cmp(const node &A, const node &B) { return A.tim < B.tim; }
    int ans[MAXN];
    int lz[MAXN<<2], sum[MAXN<<2];
    inline void upd(int i) { sum[i] = sum[i<<1] + sum[i<<1|1]; }
    inline void mt(int i, int l, int r, int mid) {
    	if(lz[i]) {
    		(lz[i<<1] += lz[i]) %= mod;
    		(lz[i<<1|1] += lz[i]) %= mod;
    		(sum[i<<1] += 1ll * lz[i] * (mid-l+1) % mod) %= mod;
    		(sum[i<<1|1] += 1ll * lz[i] * (r-mid) % mod) %= mod;
    		lz[i] = 0;
    	}
    }
    void insert(int i, int l, int r, int x, int y) {
    	if(l == x && r == y) {
    		(lz[i] += 1) %= mod;
    		(sum[i] += r-l+1) %= mod;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	mt(i, l, r, mid);
    	if(y <= mid) insert(i<<1, l, mid, x, y);
    	else if(x > mid) insert(i<<1|1, mid+1, r, x, y);
    	else insert(i<<1, l, mid, x, mid), insert(i<<1|1, mid+1, r, mid+1, y);
    	upd(i);
    }
    int query(int i, int l, int r, int x, int y) {
    	if(l == x && r == y) return sum[i];
    	int mid = (l + r) >> 1;
    	mt(i, l, r, mid);
    	int res = 0;
    	if(y <= mid) res = query(i<<1, l, mid, x, y);
    	else if(x > mid) res = query(i<<1|1, mid+1, r, x, y);
    	else res = (query(i<<1, l, mid, x, mid) + query(i<<1|1, mid+1, r, mid+1, y)) % mod;
    	upd(i);
    	return res;
    }
    inline void Modify(int x) {
    	while(x) insert(1, 1, n, dfn[top[x]], dfn[x]), x = fa[top[x]];
    }
    inline int Query(int x) {
    	int res = 0;
    	while(x) (res += query(1, 1, n, dfn[top[x]], dfn[x])) %= mod, x = fa[top[x]];
    	return res;
    }
    
    int main() {
    	read(n); read(Q);
    	memset(fir, -1, sizeof fir);
    	for(int i = 2; i <= n; ++i)
    		read(fa[i]), ++fa[i], add(fa[i], i);
    	dfs(1); dfs2(1, 1);
    	for(int i = 1, x, y, z; i <= Q; ++i) {
    		read(x), read(y), read(z); ++x, ++y, ++z;
    		q[++tot] = (node){ x-1, z, i, -1 }; //差分
    		q[++tot] = (node){  y , z, i,  1 };
    	}
    	sort(q + 1, q + tot + 1, cmp);
    	int now = 0;
    	for(int i = 1; i <= tot; ++i) {
    		while(now < q[i].tim) Modify(++now);
    		(ans[q[i].id] += q[i].flg * Query(q[i].x)) %= mod;
    	}
    	for(int i = 1; i <= Q; ++i)
    		printf("%d
    ", (ans[i]+mod)%mod);
    }
    

    2 树剖+在线+主席树

    沿用法1的思路,直接在主席树上找rr的线段树与l1l-1的线段树相减就行了.但是主席树不能下传标记,那么就把标记永久化.查询的时候在主席树上从根往下边走边统计.

    时间复杂度同样是O(nlog2n)O(nlog^2n),常数巨大…

    CODE

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long LL;
    template<typename T>inline void read(T &num) {
    	char ch; int flg = 1;
    	while((ch=getchar())<'0'||ch>'9')if(ch=='-')flg=-flg;
    	for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
    	num*=flg;
    }
    const int MAXN = 50005;
    const int mod = 201314;
    const int MAXNN = MAXN*100;
    int n, q, A, fir[MAXN], cnt;
    struct edge { int to, nxt; }e[MAXN];
    inline void add(int u, int v) {
    	e[cnt] = (edge){ v, fir[u] }, fir[u] = cnt++;
    }
    
    int son[MAXN], sz[MAXN], top[MAXN], tmr, dfn[MAXN], fa[MAXN];
    void dfs(int u) {
    	sz[u] = 1;
    	for(int i = fir[u], v; ~i; i = e[i].nxt) {
    		dfs(v=e[i].to), sz[u] += sz[v];
    		if(sz[v] > sz[son[u]]) son[u] = v;
    	}
    }
    void dfs2(int u, int tp) {
    	top[u] = tp; dfn[u] = ++tmr;
    	if(son[u]) dfs2(son[u], tp);
    	for(int i = fir[u], v; ~i; i = e[i].nxt)
    		if((v=e[i].to) != fa[u] && v != son[u])
    			dfs2(v, v);
    }
    int ch[MAXNN][2], tim[MAXNN], tot, rt[MAXN], sum[MAXNN];
    
    inline void Newnode(int i, int p) { ch[i][0] = ch[p][0], ch[i][1] = ch[p][1], sum[i] = sum[p], tim[i] = tim[p]; }
    
    void modify(int &i, int l, int r, int L, int R) {
    	Newnode(++tot, i);
    	if(L == l && r == R) { (++tim[i = tot]) %= mod; return; }
    	(sum[i = tot] += R-L+1) %= mod;
    	int mid = (l + r) >> 1;
    	if(R <= mid) modify(ch[i][0], l, mid, L, R);
    	else if(L > mid) modify(ch[i][1], mid+1, r, L, R);
    	else modify(ch[i][0], l, mid, L, mid), modify(ch[i][1], mid+1, r, mid+1, R);
    }
    inline void Modify(int &r, int x) { while(x) modify(r, 1, n, dfn[top[x]], dfn[x]), x = fa[top[x]]; }
    int query(int i, int l, int r, int L, int R) {
    	if(!i) return 0;
    	int res = 1ll * (R-L+1) * tim[i] % mod;
    	if(L == l && r == R) return (res + sum[i]) % mod;
    	int mid = (l + r) >> 1;
    	if(R <= mid) return (res + query(ch[i][0], l, mid, L, R)) % mod;
    	else if(L > mid) return (res + query(ch[i][1], mid+1, r, L, R)) % mod;
    	return (res + query(ch[i][0], l, mid, L, mid) + query(ch[i][1], mid+1, r, mid+1, R)) % mod;
    }
    int Query(int r, int x) { int res = 0; while(x) (res += query(r, 1, n, dfn[top[x]], dfn[x])) %= mod, x = fa[top[x]]; return res; }
    int main () {
    	read(n), read(q);
    	memset(fir, -1, sizeof fir);
    	for(int i = 2; i <= n; ++i)
    		read(fa[i]), ++fa[i], add(fa[i], i);
    	dfs(1), dfs2(1, 1);
    	for(int i = 1; i <= n; ++i) Modify(rt[i]=rt[i-1], i);
    	int L, R, x;
    	while(q--) {
    		read(L), read(R), read(x); ++L, ++R, ++x;
    		printf("%d
    ", (Query(rt[R], x) - Query(rt[L-1], x) + mod) % mod);
    	}
    }
    
    
  • 相关阅读:
    设计模式之里氏替换原则
    设计模式之依赖倒置原则讲解
    条款10 若不想使用编译器自动生成的函数,就该明确拒绝
    Django---常用字段和参数
    Python中abc
    Python中鸭子类型
    Python多继承的正确打开方式:mixins机制
    python新式类和经典类的区别
    Django---drf权限、频率、过滤、排序、异常处理
    删库跑路技巧 删库跑路命令
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039345.html
Copyright © 2020-2023  润新知