【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】
题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的。
然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个。如下图
而如果一条链上面有分支,也是一样:
所以我们实际上只需要把最长链上的变成一种颜色就可以了。最长链就是直径,需要改动的点就是$\frac{tot+1}{2}$,$tot$就是直径的点数。
(话说$stl$好慢aaa!!!要克制住我自己少用$map$叻!
- #include<iostream>
- #include<cstdio>
- #include<map>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- int n, a[];
- int stot, tov[], nex[], h[];
- map < pair < int, int >, int > G;
- void add ( int u, int v ) {
- tov[++stot] = v;
- nex[stot] = h[u];
- h[u] = stot;
- }
- int stot_co, tov_co[], nex_co[], h_co[];
- void add_co ( int u, int v ) {
- tov_co[++stot_co] = v;
- nex_co[stot_co] = h_co[u];
- h_co[u] = stot_co;
- }
- int fa[];
- int find ( int x ) {
- if ( x != fa[x] ) fa[x] = find ( fa[x] );
- return x;
- }
- void unionn ( int x, int y ) {
- int xx = find ( x ), yy = find ( y );
- fa[xx] = yy;
- }
- int opt, color[];
- void dfs1 ( int u, int f ) {
- for ( int i = h[u]; i; i = nex[i] ) {
- int v = tov[i];
- if ( v == f ) continue;
- color[v] = ;
- if ( a[v] == a[u] ) color[v] = color[u];
- else color[v] = ++ opt;
- dfs1 ( v, u );
- int x = find ( color[v] ), y = find ( color[u] );
- if ( color[v] != color[u] && x != y ) {
- add_co ( color[v], color[u] );
- add_co ( color[u], color[v] );
- unionn ( x, y );
- }
- }
- }
- int dis[], rt;
- void dfs ( int u, int f ) {
- for ( int i = h_co[u]; i; i = nex_co[i] ) {
- int v = tov_co[i];
- if ( v == f ) continue;
- dis[v] = dis[u] + ;
- dfs ( v, u );
- }
- if ( dis[u] > dis[rt] ) rt = u;
- }
- int main ( ) {
- freopen ( "color.in", "r", stdin );
- freopen ( "color.out", "w", stdout );
- int T;
- scanf ( "%d", &T );
- while ( T -- ) {
- G.clear ( );
- stot = , stot_co = , opt = ;
- scanf ( "%d", &n );
- for ( int i = ; i <= n; i ++ ) h[i] = ;
- for ( int i = ; i <= n; i ++ ) h_co[i] = ;
- for ( int i = ; i <= n; i ++ ) color[i] = ;
- for ( int i = ; i <= n; i ++ ) scanf ( "%d", &a[i] );
- for ( int i = ; i < n; i ++ ) {
- int u, v;
- scanf ( "%d%d", &u, &v );
- add ( u, v );
- add ( v, u );
- }
- for ( int i = ; i <= n; i ++ ) fa[i] = i;
- color[] = ++opt;
- dfs1 ( , );
- rt = ;
- for ( int i = ; i <= opt; i ++ ) dis[i] = ;
- dfs ( , );
- for ( int i = ; i <= opt; i ++ ) dis[i] = ;
- dfs ( rt, );
- printf ( "%d\n", ( dis[rt] + ) / );
- }
- return ;
- }
小模拟,考试的时候觉得状态太多,不可能重复???然后就没有写$vis$打标记,下来一加就...(辛酸泪QAQ
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- #include<queue>
- #include<map>
- using namespace std;
- int n, t[], G[][];
- map < int, int > mx, my;
- struct node {
- int x, y, opt, id;
- node ( int x = , int y = , int opt = , int id = ) :
- x ( x ), y ( y ), opt ( opt ), id ( id ) { }
- };
- queue < node > q;
- int vis[][][][];
- struct QAQ {
- int x, y;
- QAQ ( int x = , int y = ) :
- x ( x ), y ( y ) { }
- };
- QAQ print ( int x, int y, int opt, int id ) {
- for ( int i = ; i <= t[id]; i ++ ) {
- G[x][y] = ;
- x = x + mx[opt]; y = y + my[opt];
- }
- return QAQ ( x - mx[opt], y - my[opt] );
- }
- void BFS ( int sx, int sy ) {
- q.push ( node ( sx, sy + t[] - , , ) );
- QAQ a = print ( sx, sy, , );
- vis[sx][sy+t[]-][][] = ;
- while ( !q.empty ( ) ) {
- node x = q.front ( ); q.pop ( );
- if ( x.id == n ) break;
- if ( x.opt != - && x.opt != ) {
- int L = x.opt - , R = x.opt + ;
- int id = x.id + ;
- int lsx = x.x + mx[L], lsy = x.y + my[L];
- int rsx = x.x + mx[R], rsy = x.y + my[R];
- QAQ ll = print ( lsx, lsy, L, id );
- QAQ rr = print ( rsx, rsy, R, id );
- if ( !vis[ll.x][ll.y][id][L] ) {
- q.push ( node ( ll.x, ll.y, L, id ) );
- vis[ll.x][ll.y][id][L] = ;
- }
- if ( !vis[rr.x][rr.y][id][R] ) {
- q.push ( node ( rr.x, rr.y, R, id ) );
- vis[rr.x][rr.y][id][R] = ;
- }
- } else if ( x.opt == - ) {
- int L = , R = x.opt + ;
- int id = x.id + ;
- int lsx = x.x + mx[L], lsy = x.y + my[L];
- int rsx = x.x + mx[R], rsy = x.y + my[R];
- QAQ ll = print ( lsx, lsy, L, id );
- QAQ rr = print ( rsx, rsy, R, id );
- if ( !vis[ll.x][ll.y][id][L] ) {
- q.push ( node ( ll.x, ll.y, L, id ) );
- vis[ll.x][ll.y][id][L] = ;
- }
- if ( !vis[rr.x][rr.y][id][R] ) {
- q.push ( node ( rr.x, rr.y, R, id ) );
- vis[rr.x][rr.y][id][R] = ;
- }
- } else if ( x.opt == ) {
- int L = x.opt - , R = -;
- int id = x.id + ;
- int lsx = x.x + mx[L], lsy = x.y + my[L];
- int rsx = x.x + mx[R], rsy = x.y + my[R];
- QAQ ll = print ( lsx, lsy, L, id );
- QAQ rr = print ( rsx, rsy, R, id );
- if ( !vis[ll.x][ll.y][id][L] ) {
- q.push ( node ( ll.x, ll.y, L, id ) );
- vis[ll.x][ll.y][id][L] = ;
- }
- if ( !vis[rr.x][rr.y][id][R] ) {
- q.push ( node ( rr.x, rr.y, R, id ) );
- vis[rr.x][rr.y][id][R] = ;
- }
- }
- }
- }
- int main ( ) {
- freopen ( "grow.in", "r", stdin );
- freopen ( "grow.out", "w", stdout );
- scanf ( "%d", &n );
- mx[] = , mx[] = , mx[] = , mx[] = , mx[] = , mx[-] = -, mx[-] = -, mx[-] = -;
- my[] = , my[] = , my[] = , my[] = -, my[] = -, my[-] = , my[-] = , my[-] = -;
- for ( int i = ; i <= n; i ++ ) scanf ( "%d", &t[i] );
- BFS ( , );
- int ans = ;
- for ( int i = ; i < ; i ++ )
- for ( int j = ; j < ; j ++ )
- if ( G[i][j] ) ans ++;
- printf ( "%d", ans );
- }
有关串用$dp$解决是很显然的(?$idy$题解原话),定义$dp[s][t]$表示从$s$状态转移到$t$状态最少的修改数。关于状态定义代码有注释。用线段树维护区间状态转移$dp$值,每个节点保存一个矩阵,节点合并时类似$floyed$,枚举断点转移。查询时查询区间即可。
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #define oo 0x3f3f3f3f
- using namespace std;
- // 0 1 2 3 4
- // $ 2 20 201 2017
- const int N = ;
- struct Info {
- int dp[][];
- void init ( int cur ) {
- memset ( dp, 0x3f, sizeof ( dp ) );
- if ( cur == || cur == || cur == || cur == || cur == ) {
- for ( int i = ; i <= ; i ++ )
- dp[i][i] = ;
- } else if ( cur == ) {
- dp[][] = ; dp[][] = ;
- dp[][] = dp[][] = dp[][] = dp[][] = ;
- } else if ( cur == ) {
- dp[][] = ;
- dp[][] = ;
- dp[][] = dp[][] = dp[][] = dp[][] = ;
- } else if ( cur == ) {
- dp[][] = ;
- dp[][] = ;
- dp[][] = dp[][] = dp[][] = dp[][] = ;
- } else if ( cur == ) {
- dp[][] = ;
- dp[][] = ;
- dp[][] = dp[][] = dp[][] = dp[][] = ;
- } else if ( cur == ) {
- dp[][] = ;
- dp[][] = ;
- dp[][] = dp[][] = dp[][] = ;
- }
- }
- };
- Info operator + ( const Info &r, const Info &s ) {
- Info rt;
- memset ( &rt, 0x3f, sizeof ( rt ) );
- for ( int i = ; i <= ; i ++ )
- for ( int j = ; j <= ; j ++ )
- for ( int k = i; k <= j; k ++ ) {
- rt.dp[i][j] = min ( rt.dp[i][j], r.dp[i][k] + s.dp[k][j] );
- }
- return rt;
- }
- struct node {
- Info info;
- node *ls, *rs;
- } pool[N*], *tail = pool, *root;
- int a[N];
- char s[N];
- node *build ( int l, int r ) {
- node *nd = ++tail;
- if ( l == r ) {
- nd -> info.init ( a[l] );
- return nd;
- }
- int mid = ( l + r ) >> ;
- nd -> ls = build ( l, mid );
- nd -> rs = build ( mid + , r );
- nd -> info = nd -> ls -> info + nd -> rs -> info;
- return nd;
- }
- Info query ( node *nd, int l, int r, int L, int R ) {
- if ( l >= L && r <= R ) return nd -> info;
- int mid = ( l + r ) >> ;
- if ( R <= mid ) return query ( nd -> ls, l, mid, L, R );
- else if ( L > mid ) return query ( nd -> rs, mid + , r, L, R );
- else return query ( nd -> ls, l, mid, L, R ) + query ( nd -> rs, mid + , r, L, R );
- }
- int n, q;
- int query ( int l, int r ) {
- Info info = query ( root, , n, l, r );
- return info.dp[][] == oo ? - : info.dp[][];
- }
- int main ( ) {
- freopen ( "year.in", "r", stdin );
- freopen ( "year.out", "w", stdout );
- scanf ( "%s", s + );
- scanf ( "%d", &q );
- n = strlen ( s + );
- for ( int i = ; i <= n; i ++ )
- a[i] = s[i] - '';
- root = build ( , n );
- while ( q -- ) {
- int l, r;
- scanf ( "%d%d", &l, &r );
- printf ( "%d\n", query ( l, r ) );
- }
- return ;
- }
【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】的更多相关文章
- [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)
题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...
- 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径
LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...
- bzoj 3551 kruskal重构树dfs序上的主席树
强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...
- 【8.23校内测试】【贪心】【线段树优化DP】
$m$的数据范围看起来非常有问题??仔细多列几个例子可以发现,在$m<=5$的时候,只要找到有两行状态按位$&$起来等于$0$,就是可行方案,如果没有就不行. #include<i ...
- 倍增/线段树维护树的直径 hdu5993/2016icpc青岛L
题意: 给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径 点10W,询问10W,询问相互独立 Solution: 考虑线段树/倍增维护树的直径 考虑一个点集的区间 [l, r] 而我们知道了有 ...
- Snow的追寻--线段树维护树的直径
Snow终于得知母亲是谁,他现在要出发寻找母亲.王国中的路由于某种特殊原因,成为了一棵有n个节点的根节点为1的树,但由于"Birds are everywhere.",他得到了种种 ...
- HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化
题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...
- 【10.26校内测试】【状压?DP】【最小生成树?搜索?】
Solution 据说正解DP30行??? 然后写了100行的状压DP?? 疯狂特判,一算极限时间复杂度过不了aaa!! 然而还是过了....QAQ 所以我定的状态是待转移的位置的前三位,用6位二进制 ...
- 【11.8校内测试】【倒计时2天】【状压DP】【随机化?/暴力小模拟】
Solution 数据范围疯狂暗示状压,可是一开始发现状态特别难受. 将每一层的奇偶性状压,预处理所有状态的奇偶性.每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到. 所以枚举每个状 ...
随机推荐
- ahttp
# -*- coding: utf-8 -*- # @Time : 2018/8/20 14:35 # @Author : cxa # @File : chttp.py # @Software: Py ...
- 批量生成AWR报告(转载总结)
[前提] 对Oracle进行性能分析其中一个“帮手”就是Oracle的AWR报告 PS:Oracle的企业版才有AWR报告,标准版是没有的{可以导出来,但是没有数据显示} [需求] 当需要针对某个月的 ...
- Mac——mac安装软件
命令行: perl: curl -L http://xrl.us/installperlosx | bash 参考资料: https://blog.csdn.net/yuxin6866/article ...
- Zabbix3.0 API调用
Zabbix API 是什么? API简单来说是服务对外开放的一个接口,用户通过该接口传递请求,完成操作.API的背后是一组方法的集合,这些方法实现了服务对应的不同功能,调用API实际上就是换了一种方 ...
- chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息
chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息.谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接. 使用语法:chkconfig [--ad ...
- Floyd_Warshall(任意两点之间的最短路)
/* O(V^3) 案例: 1 2 2 1 3 5 2 3 1 */ #include <cstdio>#include <iostream>using namespace s ...
- Shell语言系列之一:文件处理
前言   标准输入/输出可能是软件工具设计原则里最基本的观念了.有很多UNIX程序都遵循这一设计历练.默认情况下,他们会读取标准输入,写入标准输出,并将错误信息传递给标准错误输出. & ...
- OPENSSL问题,使用fsockopen()函数提示错误
环境配置 系统环境 CentOS7.2WDCP v3.2.2 lanmp PHP 多版本 指定使用5.6 OpenSSL 1.0.2h 3 May 2016 php.ini相关设置allow_url ...
- go-互斥锁及原子函数
用于解决并发函数的竞争状态问题... package main import ( "fmt" "runtime" "sync" " ...
- js 利用事件委托解决mousedown中的click
有一个需求是这样的: 父元素div绑定一个mousedown事件,子元素a绑定一个click事件. 看解构: <div id="nav"> <a href=&qu ...