解:首先有个套路是一条边的权值是[两端点颜色不同]。这个用树剖直接维护,支持修改。

每次询问建虚树,查询虚树上每条边的权值。然后树形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 树上的毒瘤的更多相关文章

  1. [洛谷U40581]树上统计treecnt

    [洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...

  2. 洛谷 P3177 树上染色 解题报告

    P3177 [HAOI2015]树上染色 题目描述 有一棵点数为\(N\)的树,树边有边权.给你一个在\(0\) ~ \(N\)之内的正整数\(K\),你要在这棵树中选择\(K\)个点,将其染成黑色, ...

  3. 洛谷P2664 树上游戏(点分治)

    传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...

  4. 洛谷 P2664 树上游戏 解题报告

    P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...

  5. 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)

    题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...

  6. ●洛谷P2664 树上游戏

    题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...

  7. 洛谷P2664 树上游戏(点分治)

    题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...

  8. 洛谷P3178 树上操作 [HAOI2015] 树链剖分

    正解:树链剖分+线段树 解题报告: 传送门! 树链剖分+线段树算是基操了趴,,, 就无脑码码码,没有任何含金量,不需要动脑子,然后码量其实也不大,就很爽 比树剖的板子还要板子一些hhhhh 放下代码就 ...

  9. 洛谷 P3177 树上染色

    题面 题目要求将k个点染成黑色,求黑点两两距离及白点两两距离,使他们之和最大. 我们可以将距离转化为路径,然后再将路径路径拆分成边,就可以记录每条边被经过的次数,直接计算即可. 很简单对吧?那么问题来 ...

随机推荐

  1. python之路--面向对象-成员

    一 . 成员 在类中你能写的所有内容都是类的成员 class 类名: # 方法 def__init__(self, 参数1, 参数2...): # 属性变量 self.属性1 = 参数1 self.属 ...

  2. dashboard使用与访问

    #dashboard的github地址 https://github.com/kubernetes/dashboard #下载 wget https://raw.githubusercontent.c ...

  3. 老男孩python学习自修【第三天】列表用法

    列表的使用: list.append(value) 向列表增加元素 list.insert(index, value) 向列表指定元素插入元素 list.extend(newlist) 用新的列表扩展 ...

  4. OSError: mysql_config not found

    使用Python3开发一个管理平台,用MySQL数据库存放元数据.使用pip安装mysqlclient模块时出现“OSError: mysql_config not found”错误. 解决: # a ...

  5. Tembin

    1:组织机构和用户之间是多对一的关系,一个组织结构可以有多个成员,一个成员只能属于一个组织机构. 2:app里面的邀请成员:是邀请发送短信通知用户注册tembin账户,当用户去注册的时候下面就会显示所 ...

  6. How to remove ROM in MAME

    /usr/share/games/mame/roms/ /usr/local/share/games/mame/roms/ sudo rm /usr/local/share/games/mame/ro ...

  7. 学习 Spring (二) Spring 注入

    Spring入门篇 学习笔记 常用的两种注入方式 设值注入 构造注入 示例准备工作 添加 InjectionDAO: public interface InjectionDAO { void save ...

  8. JSON in SQL Server 2016

    JSON functions in SQL Server enable you to analyze and query JSON data, transform JSON to relational ...

  9. User Authentication with Angular and ASP.NET Core

    User authentication is a fundamental part of any meaningful application. Unfortunately, implementing ...

  10. Linux 部署KVM虚拟化平台

    简单介绍 KVM 是基于虚拟化扩展(Intel VT 或者 AMD-V)的 X86 硬件的开源的 Linux 原生的全虚拟化解决方案.KVM 中,虚拟机被实现为常规的 Linux 进程,由标准 Lin ...