题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的。

然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了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】的更多相关文章

  1. [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)

    题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...

  2. 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径

    LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...

  3. bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...

  4. 【8.23校内测试】【贪心】【线段树优化DP】

    $m$的数据范围看起来非常有问题??仔细多列几个例子可以发现,在$m<=5$的时候,只要找到有两行状态按位$&$起来等于$0$,就是可行方案,如果没有就不行. #include<i ...

  5. 倍增/线段树维护树的直径 hdu5993/2016icpc青岛L

    题意: 给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径 点10W,询问10W,询问相互独立 Solution: 考虑线段树/倍增维护树的直径 考虑一个点集的区间 [l, r] 而我们知道了有 ...

  6. Snow的追寻--线段树维护树的直径

    Snow终于得知母亲是谁,他现在要出发寻找母亲.王国中的路由于某种特殊原因,成为了一棵有n个节点的根节点为1的树,但由于"Birds are everywhere.",他得到了种种 ...

  7. HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化

    题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...

  8. 【10.26校内测试】【状压?DP】【最小生成树?搜索?】

    Solution 据说正解DP30行??? 然后写了100行的状压DP?? 疯狂特判,一算极限时间复杂度过不了aaa!! 然而还是过了....QAQ 所以我定的状态是待转移的位置的前三位,用6位二进制 ...

  9. 【11.8校内测试】【倒计时2天】【状压DP】【随机化?/暴力小模拟】

    Solution 数据范围疯狂暗示状压,可是一开始发现状态特别难受. 将每一层的奇偶性状压,预处理所有状态的奇偶性.每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到. 所以枚举每个状 ...

随机推荐

  1. python作业类Fabric主机管理程序开发(第九周)

    作业需求: 1. 运行程序列出主机组或者主机列表 2. 选择指定主机或主机组 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) 4. 充分使用多线程或多进程 5. 不同主机的用户名密码 ...

  2. html5优分期大学生分期购物商城模板

    链接:http://pan.baidu.com/s/1dEUAzBz 密码:j150

  3. docker 镜像导入和导出

    使用 docker commit 即可把这个容器变为一个镜像 docker commit 8d93082a9ce1 ubuntu:myubuntu 这时候 docker 容器会被创建为一个新的 Ubu ...

  4. linux系统分区参考

    UPDATE: update is used to download package information from all configured sources. UPGRADE:  upgrad ...

  5. puppet practice

    目标 试验环境有两台主机(VM)构成,一台是master,一台是agent,完成以下工作: 新建用户newuser; 安装 ubuntu-cloud-keyring package,更改文件/etc/ ...

  6. hive学习(五) 应用案例

    1.实现struct数据结构例子 1.1创建student表 create table student( id int, info struct<name:string,age:int> ...

  7. scala学习6--collection

     list的下标访问 var t = List(1,2,3,5,5) println(t(2)) map函数 println(t.map(a=> {print("***"+a ...

  8. jquery 修改样式

    //显示待办数字 function showdb(url,ID) {   jQuery.get(url,function(data,status){ if(!isNaN(data)) {  if(da ...

  9. PhpStorm函数注释的设置

    首先,PhpStorm中文件.类.函数等注释的设置在:setting->Editor->FIle and Code Template->Includes下设置即可,其中方法的默认是这 ...

  10. 【DEV C++】 Error: ld returned 1 exit status

    一般出现“ld returned 1 exit status”错误都是由于函数名称拼写错误造成的,或者在一个工程中不同的函数使用了同一个函数名,暂时还未遇到其他情况.