• 【jzoj 6276】树(线段树)(扫描线)


    题目链接:jzoj 6276

    题目大意

    给你一棵树,然后给你一些点对,问你有多少条路径满足路径上不存在任何一组给出的点对。
    一个点不算路径。

    思路

    不难看出我们可以把它弄成一两组限制条件,就是一个 dfs 序上的区间上的点都不能和一个 dfs 序区间上的点匹配。
    然后分两种情况弄限制条件:(图来自于WYC的博客,懒得画图了)
    在这里插入图片描述
    在这里插入图片描述

    然后你考虑求不合法的,拿全部减去。
    也就是你在一个二维平面上,然后用一些矩阵去覆盖,然后问你你覆盖了多少个点。

    然后这个我们考虑用扫描线做:
    你考虑用一个懒标记,记录整个区间的修改,然后如果它大于 (0),那里面所有都大于 (0),就直接返回区间长度,否则就看下面两个的和。
    然后这么搞就好了。

    代码

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #define ll long long
    
    using namespace std;
    
    struct node {
    	int to, nxt;
    }e[200001];
    int n, m, x, y;
    int le[100001], KK, deg[100001];
    int sz[100001], fa[100001][21];
    int dfn[100001], tmp, tot;
    ll ans;
    struct lne {
    	int x1, x2, y1, y2;
    }q[200001];
    struct line {
    	int x, y1, y2, op;
    }qq[200001 * 2];
    
    void add(int x, int y) {
    	e[++KK] = (node){y, le[x]}; le[x] = KK;
    	e[++KK] = (node){x, le[y]}; le[y] = KK;
    }
    
    void dfs(int now, int father) {
    	dfn[now] = ++tmp;
    	deg[now] = deg[father] + 1; 
    	sz[now] = 1; fa[now][0] = father;
    	for (int i = le[now]; i; i = e[i].nxt)
    		if (e[i].to != father) {
    			dfs(e[i].to, now);
    			sz[now] += sz[e[i].to];
    		}
    }
    
    int jump(int to, int x) {
    	for (int i = 20; i >= 0; i--)
    		if (deg[fa[x][i]] > deg[to]) x = fa[x][i];
    	return x;
    }
    
    bool cmp(line x, line y) {
    	return x.x < y.x;
    }
    
    struct XD_tree {
    	int val[100001 << 2], lzy[100001 << 2];
    	
    	void up(int now, int l, int r) {
    		if (lzy[now]) val[now] = r - l + 1;
    			else val[now] = val[now << 1] + val[now << 1 | 1];
    	}
    	
    	void insert(int now, int l, int r, int L, int R, int va) {
    		if (L <= l && r <= R) {
    			lzy[now] += va;
    			if (lzy[now]) val[now] = r - l + 1;
    				else if (l == r) val[now] = 0;
    					else val[now] = val[now << 1] + val[now << 1 | 1];
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		if (L <= mid) insert(now << 1, l, mid, L, R, va);
    		if (mid < R) insert(now << 1 | 1, mid + 1, r, L, R, va);
    		up(now, l, r);
    	}
    }T;
    
    int main() {
    //	freopen("tree.in", "r", stdin);
    //	freopen("tree.out", "w", stdout);
    	
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i < n; i++) {
    		scanf("%d %d", &x, &y);
    		add(x, y);
    	}
    	dfs(1, 0);
    	for (int i = 1; i <= 20; i++)
    		for (int j = 1; j <= n; j++)
    			fa[j][i] = fa[fa[j][i - 1]][i - 1];
    	
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d", &x, &y);
    		if (dfn[x] > dfn[y]) swap(x, y);
    		if (dfn[x] < dfn[y] && dfn[x] + sz[x] - 1 >= dfn[y]) {//有祖先关系,分成两个部分
    			int z = jump(x, y);
    			if (dfn[z] != 1) q[++tot] = (lne){1, dfn[z] - 1, dfn[y], dfn[y] + sz[y] - 1};
    			if (dfn[z] + sz[z] - 1 != n) q[++tot] = (lne){dfn[y], dfn[y] + sz[y] - 1, dfn[z] + sz[z], n};
    		}
    		else {
    			q[++tot] = (lne){dfn[x], dfn[x] + sz[x] - 1, dfn[y], dfn[y] + sz[y] - 1};
    		}
    	}
    	int plt = 0;
    	for (int i = 1; i <= tot; i++) {
    		if (q[i].x1 > q[i].x2) swap(q[i].x1, q[i].x2);
    		if (q[i].y1 > q[i].y2) swap(q[i].y1, q[i].y2);
    		qq[++plt] = (line){q[i].x1, q[i].y1, q[i].y2, 1};
    		qq[++plt] = (line){q[i].x2 + 1, q[i].y1, q[i].y2, -1};
    	}
    	tot = plt;
    	sort(qq + 1, qq + tot + 1, cmp);
    	
    	int noww = 1;
    	for (int x = 1; x <= n; x++) {
    		while (noww <= tot && qq[noww].x == x) {
    			T.insert(1, 1, n, qq[noww].y1, qq[noww].y2, qq[noww].op);
    			noww++;
    		}
    		ans += 1ll * T.val[1];
    	}
    	
    	printf("%lld", 1ll * n * (n - 1) / 2 - ans);
    	
    	return 0;
    } 
    
  • 相关阅读:
    解决tomcat CNTA-2020-0004漏洞
    简单理解程序如何控制硬件的
    【Spring】Spring Session的简单搭建与源码阅读
    【Spring】Spring,我的零散使用杂记
    CORS跨域、Cookie传递SessionID实现单点登录后的权限认证的移动端兼容性测试报告
    【Fiddler】Fiddler抓包
    一起学习Maven
    分布式系统接口调用回滚方案
    【FastDFS】FastDFS在CentOS的搭建
    【Java】Java日志框架Logback的简单例子
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/jzoj_6276.html
Copyright © 2020-2023  润新知