洛谷P4242 树上的毒瘤
解:首先有个套路是一条边的权值是[两端点颜色不同]。这个用树剖直接维护,支持修改。
每次询问建虚树,查询虚树上每条边的权值。然后树形DP,用开店的方法,每个点链加链查。
#include <bits/stdc++.h> #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex) typedef long long LL;
const int N = ; struct Edge {
int nex, v;
LL len;
}edge[N << ], EDGE[N]; int tp, TP; int e[N], top[N], fa[N], son[N], siz[N], d[N], pos[N], id[N], num, val[N], n, imp2[N];
int sum[N << ], lc[N << ], rc[N << ], tag[N << ];
int imp[N], K, stk[N], Top, RT, Time, E[N], vis[N], use[N], DEEP[N];
LL SIZ[N], ans[N], D[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} /// ------------------- tree 1 ------------------------- void DFS_1(int x, int f) { /// get fa son siz d
fa[x] = f;
siz[x] = ;
d[x] = d[f] + ;
forson(x, i) {
int y = edge[i].v;
if(y == f) continue;
DFS_1(y, x);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) {
son[x] = y;
}
}
return;
} void DFS_2(int x, int f) { /// get top pos id
top[x] = f;
pos[x] = ++num;
id[num] = x;
if(son[x]) DFS_2(son[x], f);
forson(x, i) {
int y = edge[i].v;
if(y == fa[x] || y == son[x]) continue;
DFS_2(y, y);
}
return;
} /// ------------------ seg 1 ---------------------- #define ls (o << 1)
#define rs (o << 1 | 1) inline void pushup(int o) {
lc[o] = lc[ls];
rc[o] = rc[rs];
sum[o] = sum[ls] + sum[rs] + (rc[ls] != lc[rs]);
return;
} inline void pushdown(int o) {
if(tag[o] != -) {
lc[ls] = rc[ls] = tag[ls] = tag[o];
lc[rs] = rc[rs] = tag[rs] = tag[o];
sum[ls] = sum[rs] = ;
tag[o] = -;
}
return;
} #undef ls
#undef rs void build(int l, int r, int o) {
if(l == r) {
lc[o] = rc[o] = val[id[r]];
sum[o] = ;
return;
}
int mid = (l + r) >> ;
build(l, mid, o << );
build(mid + , r, o << | );
pushup(o);
return;
} void change(int L, int R, int v, int l, int r, int o) {
if(L <= l && r <= R) {
lc[o] = rc[o] = tag[o] = v;
sum[o] = ;
return;
}
int mid = (l + r) >> ;
pushdown(o);
if(L <= mid) change(L, R, v, l, mid, o << );
if(mid < R) change(L, R, v, mid + , r, o << | );
pushup(o);
return;
} int ask(int p, int l, int r, int o) {
if(l == r) return lc[o];
int mid = (l + r) >> ;
pushdown(o);
if(p <= mid) return ask(p, l, mid, o << );
else return ask(p, mid + , r, o << | );
} int getSum(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) {
return sum[o];
}
pushdown(o);
int mid = (l + r) >> ;
if(R <= mid) return getSum(L, R, l, mid, o << );
if(mid < L) return getSum(L, R, mid + , r, o << | );
return getSum(L, R, l, mid, o << ) + getSum(L, R, mid + , r, o << | ) + (rc[o << ] != lc[o << | ]);
} inline int lca(int x, int y) {
while(top[x] != top[y]) {
if(d[top[x]] < d[top[y]])
y = fa[top[y]];
else
x = fa[top[x]];
}
return d[x] < d[y] ? x : y;
} inline int getLen(int x, int z) {
//printf("getLen %d %d \n", x, z);
int col = ask(pos[x], , n, ), ans = ;
while(top[x] != top[z]) {
ans += (col != ask(pos[x], , n, ));
ans += getSum(pos[top[x]], pos[x], , n, );
//printf("x = %d top[x] = %d col = %d ans = %d \n", x, top[x], col, ans);
col = ask(pos[top[x]], , n, );
x = fa[top[x]];
}
ans += (col != ask(pos[x], , n, ));
//printf("%d != %d \n", col, ask(pos[x], 1, n, 1));
ans += getSum(pos[z], pos[x], , n, );
//printf("return ans = %d \n", ans);
return ans;
} inline void Change(int x, int y, int v) {
while(top[x] != top[y]) {
if(d[top[x]] > d[top[y]]) {
change(pos[top[x]], pos[x], v, , n, );
x = fa[top[x]];
}
else {
change(pos[top[y]], pos[y], v, , n, );
y = fa[top[y]];
}
}
if(d[x] < d[y]) std::swap(x, y);
change(pos[y], pos[x], v, , n, );
return;
} /// ------------------- tree 2 ---------------------- inline void ADD(int x, int y) {
TP++;
EDGE[TP].v = y;
EDGE[TP].len = getLen(y, x);
//printf("getLen %d %d = %d \n", y, x, EDGE[TP].len);
EDGE[TP].nex = E[x];
E[x] = TP;
return;
} inline bool cmp(const int &a, const int &b) {
return pos[a] < pos[b];
} inline void work(int x) {
if(vis[x] == Time) return;
vis[x] = Time;
D[x] = E[x] = ;
return;
} inline void build_t() {
TP = ;
memcpy(imp + , imp2 + , K * sizeof(int));
std::sort(imp + , imp + K + , cmp);
stk[Top = ] = imp[];
work(imp[]);
for(int i = ; i <= K; i++) {
int x = imp[i], y = lca(x, stk[Top]);
work(x); work(y);
while(Top > && d[y] <= d[stk[Top - ]]) {
ADD(stk[Top - ], stk[Top]);
Top--;
}
if(y != stk[Top]) {
ADD(y, stk[Top]);
stk[Top] = y;
}
stk[++Top] = x;
}
while(Top > ) {
ADD(stk[Top - ], stk[Top]);
Top--;
}
RT = stk[Top];
return;
} void dfs_1(int x) { /// DP 1
SIZ[x] = (use[x] == Time);
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
dfs_1(y);
SIZ[x] += SIZ[y];
}
return;
} void dfs_2(int x) { /// DP 2
if(use[x] == Time) {
ans[x] = D[x];
}
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
D[y] = D[x] + SIZ[y] * EDGE[i].len;
DEEP[y] = DEEP[x] + EDGE[i].len;
//printf("dfs_2 D %d = %lld * %lld = %lld \n", y, SIZ[y], EDGE[i].len, D[y]);
dfs_2(y);
}
return;
} inline void cal() {
build_t();
dfs_1(RT);
DEEP[RT] = ;
dfs_2(RT);
return;
} int main() {
memset(tag, -, sizeof(tag));
int q;
scanf("%d%d", &n, &q);
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
}
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y); add(y, x);
}
DFS_1(, );
DFS_2(, );
build(, n, ); for(int i = , f, x, y, z; i <= q; i++) {
scanf("%d%d", &f, &x);
if(f == ) {
scanf("%d%d", &y, &z);
Change(x, y, z);
}
else {
Time++;
K = x;
for(int j = ; j <= K; j++) {
scanf("%d", &imp2[j]);
use[imp2[j]] = Time;
}
cal();
LL SUM = ;
for(int i = ; i <= K; i++) {
SUM += DEEP[imp2[i]];
//printf("D %d = %lld \n", imp2[i], D[imp2[i]]);
}
//printf("SUM = %lld \n", SUM);
for(int i = ; i <= K; i++) {
printf("%lld ", SUM + K * DEEP[imp2[i]] - * ans[imp2[i]] + K);
}
puts("");
}
}
return ;
}
AC代码
洛谷P4242 树上的毒瘤的更多相关文章
- [洛谷U40581]树上统计treecnt
[洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...
- 洛谷 P3177 树上染色 解题报告
P3177 [HAOI2015]树上染色 题目描述 有一棵点数为\(N\)的树,树边有边权.给你一个在\(0\) ~ \(N\)之内的正整数\(K\),你要在这棵树中选择\(K\)个点,将其染成黑色, ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)
题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- 洛谷P3178 树上操作 [HAOI2015] 树链剖分
正解:树链剖分+线段树 解题报告: 传送门! 树链剖分+线段树算是基操了趴,,, 就无脑码码码,没有任何含金量,不需要动脑子,然后码量其实也不大,就很爽 比树剖的板子还要板子一些hhhhh 放下代码就 ...
- 洛谷 P3177 树上染色
题面 题目要求将k个点染成黑色,求黑点两两距离及白点两两距离,使他们之和最大. 我们可以将距离转化为路径,然后再将路径路径拆分成边,就可以记录每条边被经过的次数,直接计算即可. 很简单对吧?那么问题来 ...
随机推荐
- css3的clip-path方法剪裁实现
本例讲解如何通过clip-path把一个div(元素,可以是图片等)裁切成不同的形状,这里以一个div为例宽高均为300px 注意:不支持IE和Firefox,支持webkit浏览器,在现代浏览器中需 ...
- Golang的方法传递值应该注意的地方
其实最近看了不少Golang接口以及方法的阐述都有一个地方没说得特别明白.就是在Golang编译隐式转换传递给方法使用的时候,和调用函数时的区别. 我们都知道,在我们为一个类型变量申明了一个方法的时候 ...
- LODOP打印css样式rgba显示黑色区块
当LODOP打印html超文本出现问题的时候,要删减排查一下样式,查看Lodop传入的内部的html超文本和样式,可查看本博客另一篇博文:删减发现有问题的样式,并解决该问题,尽量使用通用的css样式, ...
- 做接口自动化时候,一些登录头信息可以通过aop的方式进行增强
做接口自动化时候,一些登录头信息可以通过aop的方式进行增强
- APP需求调研、对比
二.人脸验证 1.芝麻认证 : 0.4元/次,需要企业企业认证.不能有与芝麻信用类似的业务,如:保险... 2.旷视 : 0.5/次.企业认证.业务限制 3. 百度人脸识别 : 企业认证. 4.科大 ...
- P1020 导弹拦截
思路:贪心思路 拿比飞来的导弹高并且高度和飞来的导弹最相近的拦截系统去接, 如果全部都比导弹矮,那就新开一个拦截系统 #include<cstdio> #include<string ...
- AHOI2013 差异 【后缀数组】
题目分析: 求出height以后很明显跨越最小height的一定贡献是最小height,所以对于区间找出最小height再将区间对半分. 代码: #include<bits/stdc++.h&g ...
- 用二分法定义平方根函数(Bisection method Square Root Python)
Python里面有内置(Built-in)的平方根函数:sqrt(),可以方便计算正数的平方根.那么,如果要自己定义一个sqrt函数,该怎么解决呢? 解决思路: 1. 大于等于1的正数n的方根,范围 ...
- DNS 透明代理
DNS 透明代理 一.使用DNS负载均衡虚拟服务器(DNS * 53)的方式 --- 推荐使用的方式 注意:只会代理跨内网网段的DNS查询请求 ---------------------------- ...
- flask报错:werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'single' instead?
错误代码 参考:https://blog.csdn.net/qq_27468251/article/details/81359701 改为