洛谷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个点染成黑色,求黑点两两距离及白点两两距离,使他们之和最大. 我们可以将距离转化为路径,然后再将路径路径拆分成边,就可以记录每条边被经过的次数,直接计算即可. 很简单对吧?那么问题来 ...
随机推荐
- (二)类数组对象HTMLCollection
HTMLCollection 表示 HTML 元素的集合. 下面的几种方式将返回 HTMLCollection对象: html: <body> <ul id="box&qu ...
- Slave_SQL_Running:No的两种解决办法
进入slave服务器,运行: mysql> show slave status\G ....... Relay_Log_File: localhost-relay-bin. Relay_Log_ ...
- DAY03、基本数据类型和运算符
一.基本数据类型的使用 1.整型int: 作用:用来记录年龄.等级.数量 定义:age=18 使用:数学运算与比较运算: 例:print(10>3) print(10/3) 2.浮点型float ...
- oracle11g安装教程完整版
来自: https://www.2cto.com/database/201701/588135.html 64位WIN7+oracle11g+plsql安装 1.下载Oracle 11g R2 for ...
- 51-nod(1443)(最短路)
解题思路:最短路+记录前驱和,刚开始一直以为是最短路+MST,结果发现,因为无向图的原因,有些边权很小的边再最短路处理后可能这条边也符合某两个点的最短路径,所以我们觉得这条边也是可以在MST处理中使用 ...
- Ubuntu下安装tomcat
下面记录了Ubuntu 16.04下安装Tomcat 8.5.9的过程步骤. 1.到官网下载tomcat8.5.9,选择格式为tar.gz.2.通过ftp将下载的tomcat8.5.9压缩包上传到ub ...
- python----函数的动态传参
函数的动态传参 *args 将所有的实参的位置参数聚合到一个元组,并将这个元组赋值给args 有些时候,对于函数,传入的实参数量可能是不固定的,也就是动态的,这个时候我们就需要用到函数的动态传参.下面 ...
- 洛谷P2822 组合数问题
输入输出样例 输入样例#1: 1 2 3 3 输出样例#1: 1 输入样例#2: 2 5 4 5 6 7 输出样例#2: 0 7 说明 [样例1说明] 在所有可能的情况中,只有C_2^1 = 2C21 ...
- Newtonsoft.Json 概述
有时候,在前后台数据交互或者APP与后台交互的时候,我们通常会使用Json进行数据交互,为此会使用到Newtonsoft.Json.dll 这个类库,这个类库非微软官方,但是下载量已经超过了数十万次, ...
- Longest Ordered Subsequence POJ - 2533 最长上升子序列dp
题意:最长上升子序列nlogn写法 #include<iostream> #include<cstdio> #include<cstring> #include&l ...