「UNR#1」奇怪的线段树

一道好题,感觉解法非常自然。

首先我们只需要考虑一次染色最下面被包含的那些区间,因为把无解判掉以后只要染了一个节点,它的祖先也一定被染了。然后发现一次染色最下面的那些区间一定是一段连续的左儿子+一段连续的右儿子。

证明的话可以看官方题解,感性理解的话不难,同时,任意一段连续的左儿子+右儿子也对应一个区间。定义一个左儿子区间 \([l_i,r_i]\) 的后继是所有 \(r_i=l_i+1\) 的左儿子和右儿子,一个右儿子区间 \([l_i,r_i]\) 的后继是所有 \(r_i=l_i+1\) 的右儿子区间,不难发现这是一个DAG。那么这张图的一条路径就对应了原图的一个染色区间,也就是要求这个DAG的最小路径覆盖,优化建图+上下界最小流即可。

code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 200005, M = 200005;
int L[N], R[N], col[N], low[N], isl[N], n, NS, NT, cnt = 1;
inline void init(int u, int l, int r){
L[u] = l, R[u] = r;
if(l == r)
return (void) (read(col[u]), low[u] = col[u]);
int mid, lc, rc;
read(col[u]), read(mid);
init(lc = ++cnt, l, mid), init(rc = ++cnt, mid + 1, r);
isl[lc] = 1;
if(!col[u] && (col[lc] || col[rc])){
puts("OwO"); exit(0);
}
low[u] = col[u] && (!col[lc]) && (!col[rc]);
}
namespace flow{
queue<int> q;
int a[M], cap[M], nxt[M], head[N], cur[N], dis[N], S, T, cnt = 1;
inline void addedge(int x, int y, int z){
a[++cnt] = y, cap[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
a[++cnt] = x, cap[cnt] = 0, nxt[cnt] = head[y], head[y] = cnt;
}
inline int bfs(){
memset(dis, -1, sizeof(dis)), dis[S] = 0, q.push(S);
for(; !q.empty(); q.pop()){
int u = q.front();
for(int p = head[u]; p; p = nxt[p]){
int v = a[p];
if(~dis[v] || !cap[p]) continue;
dis[v] = dis[u] + 1, q.push(v);
}
}
return ~dis[T];
}
inline int dfs(int u, int flow){
if(u == T || !flow) return flow;
int used = 0;
for(int &p = cur[u]; p; p = nxt[p]){
int v = a[p];
if(dis[v] != dis[u] + 1 || !cap[p]) continue;
int x = dfs(v, min(flow, cap[p]));
used += x, flow -= x, cap[p] -= x, cap[p^1] += x;
if(!flow) break;
}
return used;
}
inline void setflow(int x, int y){ S = x, T = y; }
inline int getflow(){
int res = 0;
for(; bfs(); res += dfs(S, inf))
memcpy(cur, head, sizeof(cur));
return res;
}
}
inline void addedge(int x, int y, int a, int b){
flow::addedge(NS, y, a);
flow::addedge(x, NT, a);
flow::addedge(x, y, b - a);
}
int main(){
read(n);
init(1, 1, n);
int S = n * 6 + 1, T = S + 1;
NS = T + 1, NT = NS + 1;
for(int i = 1; i < (n << 1); i++) if(col[i]){
addedge(i, i + (n << 1), low[i], inf);
addedge(L[i] + (n << 2), i, 0, inf);
addedge(i + (n << 1), T, 0, inf);
addedge(S, i, 0, inf);
if(isl[i]){
if(R[i] < n)
addedge(i + (n << 1), R[i] + 1 + (n << 2) + n, 0, inf);
addedge(L[i] + (n << 2) + n, i, 0, inf);
}
else if(R[i] < n)
addedge(i + (n << 1), R[i] + 1 + (n << 2), 0, inf);
}
flow::setflow(NS, NT);
flow::getflow();
flow::addedge(T, S, inf);
cout << flow::getflow() << endl;
return 0;
}

「UNR#1」奇怪的线段树的更多相关文章

  1. loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增

    题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...

  2. LOJ 2980 「THUSCH 2017」大魔法师——线段树

    题目:https://loj.ac/problem/2980 线段树维护矩阵. 然后是 30 分.似乎是被卡常了?…… #include<cstdio> #include<cstri ...

  3. [UOJ] #217. 【UNR #1】奇怪的线段树

    题解见大佬博客 我的丑陋代码: #include<cstdio> #include<cstring> #include<cstdlib> inline int re ...

  4. 「CQOI2006」简单题 线段树

    「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...

  5. 「AHOI2014/JSOI2014」奇怪的计算器

    「AHOI2014/JSOI2014」奇怪的计算器 传送门 我拿到这题首先是懵b的,因为感觉没有任何性质... 后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发 ...

  6. #3144. 「APIO 2019」奇怪装置

    #3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...

  7. 「UNR#2」黎明前的巧克力

    「UNR#2」黎明前的巧克力 解题思路 考虑一个子集 \(S\) 的异或和如果为 \(0\) 那么贡献为 \(2^{|S|}\) ,不难列出生产函数的式子,这里的卷积是异或卷积. \[ [x^0]\p ...

  8. [UOJ UNR#1]奇怪的线段树

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 原题可以到UOJ看,传送门 如果存在一个点是白的,却有儿子是黑的,显然无解. 不然的话,只要所有黑色的“黑叶子”节点,即没有黑色的儿子的节点 ...

  9. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

随机推荐

  1. JavaScript正则表达式进阶指南

    摘要:正则表达式是程序员的必备技能,想不想多学几招呢? 本文用JavaScript的exec方法来测试正则表达式. 例如,正则表达式**/F.*g/会匹配"以F开头,以g结尾的字符串&quo ...

  2. 8皇后问题SQL求解(回溯算法)

    问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一 ...

  3. Html引入百度富文本编辑器ueditor及自定义工具栏

    在日常工作用,肯定有用到富文本编辑器的时候,富文本编辑器功能强大使用方便,我用的是百度富文本编辑器,首先需要下载好百度编辑器的demo, 然后创建ueditor.html文件,引入百度编辑器,然后在h ...

  4. php模板模式(template design)

    没有写停止条件,所以会一直运行哟. <?php /* The template design pattern defines the program skeleton of an algorit ...

  5. NiFi使用总结 一 hive到hive的PutHiveStreaming processor和SelectHiveQL

    我说实话,NiFi的坑真的挺多的... 1.PutHiveStreaming processor的使用 具体配置可参考:https://community.hortonworks.com/articl ...

  6. 09-赵志勇机器学习-k-means

    (草稿) k-means: 1. 随机选取n个中心 2. 计算每个点到各个中心的距离 3. 距离小于阈值的归成一类. 4. 计算新类的质心,作为下一次循环的n个中心 5. 直到新类的质心和对应本次循环 ...

  7. JDOJ 1133 分段公司利润

    JDOJ 1133: 分段公司利润 JDOJ传送门 Description 企业发放的奖金根据利润提成.利润低于或等于100000元的,奖金可提10%; 利润高于100000元,低于200000元(1 ...

  8. 11.面试思路&画图让抽象具体化(2)

    面试思路 题一:[二叉树的镜像] 操作给定的二叉树,将其变换为源二叉树的镜像. 分析:使用递归=>边界条件:节点为空,交换当前节点的左右节点. /** public class TreeNode ...

  9. react使用ant design pro时的滑动图片组件

    react的滑动图片验证,是基于https://segmentfault.com/a/1190000018309458?utm_source=tag-newest做的修改,改动的主要有以下几点: 1. ...

  10. C# 委托的本质

    它本质是一个方法的容器 委托 只是 一件衣服, 在所有将委托做参数的地方 ,首先想到的是放一个对应的方法进来.