【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 数据范围疯狂暗示状压,可是一开始发现状态特别难受. 将每一层的奇偶性状压,预处理所有状态的奇偶性.每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到. 所以枚举每个状 ...
随机推荐
- Tornado/Python 学习笔记(一)
1.源代码下载及安装:http://www.tornadoweb.org/en/stable/ 2.python中xmlrpc库官方文档:https://docs.python.org/3/libra ...
- 【转载】WebDriver(C#)之十点使用心得
使用Selenium WebDriver驱动浏览器测试的过程中多多少少会遇到一些折腾人的问题,总结了一部分,做下分享. 一.隐藏元素处理(element not visible) 使用WebDrive ...
- videojs做直播、弹幕
从上一年开始,我们开始接触直播,现在直播成本真的很低,很多CDN供应商都有提供,本文只是大概讲述播放器这个话题. 开始调研 播放格式,我挑了三种.分别是HLS,RTMP,HTTP-FLV. 下面简单说 ...
- 121.Best Time to Buy and Sell Stock---dp
题目链接:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/ 题目大意:给出一串数组,找到差值最大的差 ...
- Python递归 — — 二分查找、斐波那契数列、三级菜单
一.二分查找 二分查找也称之为折半查找,二分查找要求线性表(存储结构)必须采用顺序存储结构,而且表中元素顺序排列. 二分查找: 1.首先,将表中间位置的元素与被查找元素比较,如果两者相等,查找结束,否 ...
- docker swarm join 报错
[peter@minion ~]$ docker swarm join --token SWMTKN-1-3mj5po3c7o04le7quhkdhz6pm9b8ziv3qe0u7hx0hrgxsna ...
- Spring如何解析Dubbo标签
1. 要了解Dubbo是如何解析标签的,首先要清楚一点就是Spring如何处理自定义标签的,因为Dubbo的标签可以算是Spring自定义标签的一种情况: 2. Spring通过两个接口来解析自定义的 ...
- HDU 4507 吉哥系列故事――恨7不成妻(数位DP+结构体)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4507 题目大意:如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关 1.整数中某一位是7: ...
- HDU 1043 Eight(反向BFS+打表+康托展开)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目大意:传统八数码问题 解题思路:就是从“12345678x”这个终点状态开始反向BFS,将各 ...
- 交通运输线(LCA)
题目大意: 战后有很多城市被严重破坏,我们需要重建城市.然而,有些建设材料只能在某些地方产生.因此,我们必须通过城市交通,来运送这些材料的城市.由于大部分道路已经在战争期间完全遭到破坏,可能有两个城市 ...