其他分享
首页 > 其他分享> > Jzoj P6275 小L的数列___线段树+扫描线+lca

Jzoj P6275 小L的数列___线段树+扫描线+lca

作者:互联网

题目大意:

有一棵n个节点的无根树,给出其中的m对点对<x,y>。问有多少条树上的简单路径<u,v>满足该路径上不存在任何一对给出的点对<x,y>。
这里我们认为路径<u,v>和<v,u>是相同的。并且对于题目中给出的点对<x,y>满足x!=y,对于你要计数的路径<u,v>满足u!=v(即单点不算答案)。
在这里插入图片描述

分析:

考虑总方案数减去不合法方案数
以1为根跑出一棵树,并记下dfs序以及子树大小,然后我们分别讨论
一个点对(x,y),设deepy&gt;=deepxdeep_y&gt;=deep_xdeepy​>=deepx​
能造成的不合法方案数,
lca(x,y)=xlca(x,y)=xlca(x,y)=x,
那么x与y路径下的x的儿子zzz,设dfs序为lll,
显然子树y的任意一个点,与除了子树y以及x到y路径上的点以外的其他点配对,都必定产生点对(x,y)(x,y)(x,y)
而子树y的dfs序是连续的一段[dfny,dfny+szy1][dfn_y,dfn_y+sz_y-1][dfny​,dfny​+szy​−1]
那么与他能配对的点显然就是除了子树zzz以外的所有点,
那么这些点的dfs序其实就是[1,dfnz1][1,dfn_z-1][1,dfnz​−1]和[dfnz+szz,n][dfn_z+sz_z,n][dfnz​+szz​,n]
lca(x,y)!=xlca(x,y)!=xlca(x,y)!=x
则他们分别位于lca的不同子树中,
那么我们可以发现,不合法的方案就是子树xxx中的点与子树yyy中的点配对
就是dfs序为[dfnx,dfnx+szx1][dfn_x,dfn_x+sz_x-1][dfnx​,dfnx​+szx​−1]的点和dfs序为[dfny,dfny+szy1][dfn_y,dfn_y+sz_y-1][dfny​,dfny​+szy​−1]的点配对
由于不合法的方案数这样统计可能会出现重复
因为计算过程中我们是根据dfs序的长度(因为dfs序总是连续的一段出现)相乘计算,那么我们可以将这个映射到二维平面上去
即矩形[ax,ay,bx,by][ax,ay,bx,by][ax,ay,bx,by]表示dfs序为[ax,ay][ax,ay][ax,ay]的点与dfs序为[bx,by][bx,by][bx,by]的点配对
当然不要忘了矩形[bx,by,ax,ay][bx,by,ax,ay][bx,by,ax,ay]也要覆盖
那么我们计算他们的交集图形的面积即可,这个用扫描线和线段树解决
因为我们重复覆盖了,最后得到的结果除以2即为不合法方案数
而不考虑有点对时的总方案数就是n(n1)/2n*(n-1)/2n∗(n−1)/2
相减即可

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring> 
#include <algorithm>

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define lson(x) x * 2
#define rson(x) x * 2 + 1

#define N 100005

using namespace std;  

typedef long long ll;

struct Code {
	int To, nxt;
}e[N*2];
struct Node {  
    int h, l, r, mazy;    
}C[N*5];  
struct Note {  
    int l, r, num, dde;
}a[N*5];
int f[N][35], deep[N], dfn[N], sz[N], ls[N], n, m, cnt, tot, cdp, edr;
ll ans = 0;

void Addedge(int u, int v) {
	e[++cnt].To = v, e[cnt].nxt = ls[u], ls[u] = cnt;
	e[++cnt].To = u, e[cnt].nxt = ls[v], ls[v] = cnt;
}

void dfs(int x, int father) {
	dfn[x] = ++tot;
	sz[x] = 1;
    f[x][0] = father;
    rep(i, 1, 30) f[x][i] = f[f[x][i - 1]][i - 1];
	for (int i = ls[x]; i; i = e[i].nxt) {
		if (e[i].To == father) continue;
		deep[e[i].To] = deep[x] + 1;
		dfs(e[i].To, x); 
		sz[x] += sz[e[i].To];
	}
}


int Get_lca(int x, int y) {
    rwp(i, 30, 0)
         if (deep[f[x][i]] >= deep[y]) x = f[x][i];
    if (x == y) return x;
    rwp(i, 30, 0) 
         if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}

void Add(int ax, int bx, int ay, int by) {
	if (ax > bx || ay > by) return;
	C[++edr].h = ay, C[edr].l = ax, C[edr].r = bx, C[edr].mazy = 1;
	C[++edr].h = by + 1, C[edr].l = ax, C[edr].r = bx, C[edr].mazy = -1;
	C[++edr].h = ax, C[edr].l = ay, C[edr].r = by, C[edr].mazy = 1;
	C[++edr].h = bx + 1, C[edr].l = ay, C[edr].r = by, C[edr].mazy = -1;
} 

bool cmp(Node aa, Node bb) {
	return aa.h < bb.h;
}

void update(int x) {
	a[x].num = 0;
	if (a[lson(x)].dde > 0) a[x].num += (a[lson(x)].r - a[lson(x)].l + 1); else a[x].num += a[lson(x)].num;
	if (a[rson(x)].dde > 0) a[x].num += (a[rson(x)].r - a[rson(x)].l + 1); else a[x].num += a[rson(x)].num;
}

void Build(int x, int l, int r) {
	if (l == r) {
		a[x].l = l; a[x].r = l; return;
	}
	int mid = (l + r) >> 1;
	Build(lson(x), l, mid);
	Build(rson(x), mid + 1, r);
	a[x].l = a[lson(x)].l;
	a[x].r = a[rson(x)].r;
}

void change(int x, int l, int r, int p, int q, int num) {
	if (r < p || l > q) return;
	if (p <= l && r <= q) {
		a[x].dde += num; return;
	}
	int mid = (l + r) >> 1;
	change(lson(x), l, mid, p, q, num);
	change(rson(x), mid + 1, r, p, q, num);
	update(x);
}

int main() { 
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout); 
	scanf("%d %d", &n, &m);
	int u, v;
	rep(i, 1, n - 1) {
		scanf("%d %d", &u, &v); Addedge(u, v);
    }
	deep[1] = 1; dfs(1, 0);
	rep(i, 1, m) {
		scanf("%d %d", &u, &v);
        if (deep[u] < deep[v]) swap(u, v);
		int llc = Get_lca(u, v);
        if (v == llc) {
        	int orz = u;
            rwp(i, 30, 0)
                if (deep[f[orz][i]] >= deep[v] + 1) orz = f[orz][i];
            Add(dfn[u], dfn[u] + sz[u] - 1, 1, dfn[orz] - 1);
			Add(dfn[u], dfn[u] + sz[u] - 1, dfn[orz] + sz[orz], n);      
		} else {
			Add(dfn[u], dfn[u] + sz[u] - 1, dfn[v], dfn[v] + sz[v] - 1);
		}
    }  
    Build(1, 1, n);
    sort(C + 1, C + edr + 1, cmp);
    int L = 1;
    rep(i, 1, n) {
    	while (C[L].h == i && L <= edr) change(1, 1, n, C[L].l, C[L].r, C[L].mazy), L++;
    	ans = (ll)ans + a[1].num; 
    	if (L > edr) break;
    }
    ans = (ll)n * (n - 1) / 2 - ans / 2;
    printf("%lld\n", ans);  
    return 0;  
}

标签:Jzoj,int,edr,dfn,P6275,扫描线,ay,ax,bx
来源: https://blog.csdn.net/Gx_Man_VIP/article/details/98777893