题目传送门

题意:有一棵数,每个节点有颜色,黑色或者白色,树边有边权,现在有2个操作,1修改某个点的颜色, 2询问2个白点的之前的路径权值最大和是多少。

题解:

边分治思路。

1.重构图。 因为边分治在菊花图的情况下情况不理想,所以需要先把图重新构建一下,是每个点的度数不超过3。

2.找在新图里面  一条边使得 断开这条边的情况下,左右2新树使得较大的那个子树是所有情况下的最小值。

3.开2个优先队列去维护左边新树的白点的最大值, 右边新树的所有白点的最大值, 然后 左边白点+右边白点+中间边就是最大值。

4.对于2个新图都执行 2-3的操作。

代码:

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
struct Node{
int head[N]; int to[N<<];
int ct[N<<]; int nt[N<<];
int tot;
void init(){
tot = ;
memset(head, -, sizeof(head));
return ;
};
void add(int u, int v, int val){
to[tot] = v; ct[tot] = val;
nt[tot] = head[u]; head[u] = tot++;
return ;
}
}e[];
int n, u, v, w;
void rebuild(int o, int u){
int ff = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
v = e[].to[i], w = e[].ct[i];
if(v == o) continue;
if(!ff){
e[].add(u, v, w);
e[].add(v, u, w);
ff = u;
}
else {
++n;
e[].add(ff, n, );
e[].add(n, ff, );
e[].add(v, n, w);
e[].add(n, v, w);
ff = n;
}
rebuild(u, v);
}
return ;
}
vector<pll> vc[N];
priority_queue<pll> pq[N<<][]; int wedge[N<<];
int white[N], sz[N];
int cut[N<<];
int id, maxnum = ;
void get_edge(int o, int u, int num){
sz[u] = ;
int tmp = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
get_edge(u, v, num);
sz[u] += sz[v];
tmp = max(num-sz[v], sz[v]);
if(tmp < maxnum){
id = i;
maxnum = tmp;
}
}
return ;
}
int k = , op;
void dfs(int o, int u, int w){
sz[u] = ;
if(white[u]){
pq[k][op].push(pll(w, u));
if(op == ) vc[u].push_back(pll(-k, w));
else vc[u].push_back(pll(k, w));
}
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
dfs(u, v, w+e[].ct[i]);
sz[u] += sz[v];
}
return ;
}
int ans[N], lch[N], rch[N];
void update(int k){
while(!pq[k][].empty() && !white[pq[k][].top().se]) pq[k][].pop();
while(!pq[k][].empty() && !white[pq[k][].top().se]) pq[k][].pop();
if(pq[k][].empty() || pq[k][].empty())
ans[k] = ;
else {
int val1 = pq[k][].top().fi, val2 = pq[k][].top().fi;
int sum = val1 + val2 + wedge[k];
ans[k] = max(sum, );
}
if(lch[k]) ans[k] = max(ans[k], ans[lch[k]]);
if(rch[k]) ans[k] = max(ans[k], ans[rch[k]]);
return ;
}
int solve(int u, int num){
if(num == ) return ;
maxnum = inf;
get_edge(, u, num);
int now = ++k, nid = id;
cut[nid >> ] = ;
wedge[k] = e[].ct[nid];
op = ;
dfs(, e[].to[nid], );
op = ;
dfs(, e[].to[nid^], );
lch[now] = solve(e[].to[nid], sz[e[].to[nid]]);
rch[now] = solve(e[].to[nid^], sz[e[].to[nid^]]);
update(now);
return now;
}
void setWhite(int u){
for(int i = vc[u].size()-; i >= ; --i){
pll tmp = vc[u][i];
int k = tmp.fi, ct = tmp.se;
if(k < ) pq[-k][].push(pll(ct, u));
else pq[k][].push(pll(ct, u));
update(abs(k));
}
return ;
}
void setBlack(int u){
for(int i = vc[u].size()-; i >= ; --i)
update(abs(vc[u][i].fi));
return ;
}
int main(){
scanf("%d", &n);
int white_num = n, q;
char op[];
e[].init(); e[].init();
for(int i = ; i < n; i++){
scanf("%d%d%d", &u, &v, &w);
e[].add(u, v, w);
e[].add(v, u, w);
white[i] = ;
}
white[n] = ;
rebuild(, );
solve(, n);
scanf("%d", &q);
while(q--){
scanf("%s", op);
if(op[] == 'A') {
if(white_num == ) puts("They have disappeared.");
else if(white_num == ) puts("");
else printf("%d\n", ans[]);
}
else {
scanf("%d", &u);
white[u] ^= ;
if(white[u])
setWhite(u), ++white_num;
else
setBlack(u), --white_num;
}
}
return ;
}
 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
struct Node{
int head[N]; int to[N<<];
int ct[N<<]; int nt[N<<];
int tot;
void init(){
tot = ;
memset(head, -, sizeof(head));
return ;
};
void add(int u, int v, int val){
to[tot] = v; ct[tot] = val;
nt[tot] = head[u]; head[u] = tot++;
return ;
}
}e[];
int n, u, v, w;
void rebuild(int o, int u){
int ff = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
v = e[].to[i], w = e[].ct[i];
if(v == o) continue;
if(!ff){
e[].add(u, v, w);
e[].add(v, u, w);
ff = u;
}
else {
++n;
e[].add(ff, n, );
e[].add(n, ff, );
e[].add(v, n, w);
e[].add(n, v, w);
ff = n;
}
rebuild(u, v);
}
return ;
}
vector<pll> vc[N];
priority_queue<pll> pq[N<<][]; int wedge[N<<];
int white[N], sz[N];
int cut[N<<];
int id, maxnum = ;
void get_edge(int o, int u, int num){
sz[u] = ;
int tmp = ;
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
get_edge(u, v, num);
sz[u] += sz[v];
tmp = max(num-sz[v], sz[v]);
if(tmp < maxnum){
id = i;
maxnum = tmp;
}
}
return ;
}
int k = , op;
void dfs(int o, int u, int w){
sz[u] = ;
if(white[u]){
pq[k][op].push(pll(w, u));
if(op == ) vc[u].push_back(pll(-k, w));
else vc[u].push_back(pll(k, w));
}
for(int i = e[].head[u]; ~i; i = e[].nt[i]){
int v = e[].to[i];
if(v == o || cut[i>>]) continue;
dfs(u, v, w+e[].ct[i]);
sz[u] += sz[v];
}
return ;
}
int ans[N], lch[N], rch[N];
void update(int k){
while(!pq[k][].empty() && !white[pq[k][].top().se]) pq[k][].pop();
while(!pq[k][].empty() && !white[pq[k][].top().se]) pq[k][].pop();
if(pq[k][].empty() || pq[k][].empty())
ans[k] = ;
else {
int val1 = pq[k][].top().fi, val2 = pq[k][].top().fi;
int sum = val1 + val2 + wedge[k];
ans[k] = max(sum, );
}
if(lch[k]) ans[k] = max(ans[k], ans[lch[k]]);
if(rch[k]) ans[k] = max(ans[k], ans[rch[k]]);
return ;
}
int solve(int u, int num){
if(num == ) return ;
maxnum = inf;
get_edge(, u, num);
int now = ++k, nid = id;
cut[nid >> ] = ;
wedge[k] = e[].ct[nid];
op = ;
dfs(, e[].to[nid], );
op = ;
dfs(, e[].to[nid^], );
lch[now] = solve(e[].to[nid], sz[e[].to[nid]]);
rch[now] = solve(e[].to[nid^], sz[e[].to[nid^]]);
update(now);
return now;
}
void setWhite(int u){
for(int i = vc[u].size()-; i >= ; --i){
pll tmp = vc[u][i];
int k = tmp.fi, ct = tmp.se;
if(k < ) pq[-k][].push(pll(ct, u));
else pq[k][].push(pll(ct, u));
update(abs(k));
}
return ;
}
void setBlack(int u){
for(int i = vc[u].size()-; i >= ; --i)
update(abs(vc[u][i].fi));
return ;
}
int main(){
scanf("%d", &n);
int white_num = n, q;
char op[];
e[].init(); e[].init();
for(int i = ; i < n; i++){
scanf("%d%d%d", &u, &v, &w);
e[].add(u, v, w);
e[].add(v, u, w);
white[i] = ;
}
white[n] = ;
rebuild(, );
solve(, n);
scanf("%d", &q);
while(q--){
scanf("%s", op);
if(op[] == 'A') {
if(white_num == ) puts("They have disappeared.");
else if(white_num == ) puts("");
else printf("%d\n", ans[]);
}
else {
scanf("%d", &u);
white[u] ^= ;
if(white[u])
setWhite(u), ++white_num;
else
setBlack(u), --white_num;
}
}
return ;
}

SPOJ - QTREE4 Query on a tree IV 边分治的更多相关文章

  1. SPOJ QTREE4 - Query on a tree IV 树分治

    题意: 给出一棵边带权的树,初始树上所有节点都是白色. 有两种操作: C x,改变节点x的颜色,即白变黑,黑变白 A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为0). 分析: ...

  2. SPOJ QTREE4 - Query on a tree IV

    You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3. ...

  3. SPOJ QTREE4 Query on a tree IV ——动态点分治

    [题目分析] 同bzoj1095 然后WA掉了. 发现有负权边,只好把rmq的方式改掉. 然后T了. 需要进行底(ka)层(chang)优(shu)化. 然后还是T 下午又交就A了. [代码] #in ...

  4. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

    意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...

  5. SP2666 QTREE4 - Query on a tree IV(LCT)

    题意翻译 你被给定一棵n个点的带边权的树(边权可以为负),点从1到n编号.每个点可能有两种颜色:黑或白.我们定义dist(a,b)为点a至点b路径上的权值之和. 一开始所有的点都是白色的. 要求作以下 ...

  6. SPOJ - QTREE5 Query on a tree V 边分治

    题目传送门 题意:给你一棵树, 然后树上的点都有颜色,且原来为黑,现在有2个操作,1 改变某个点的颜色, 2 询问树上的白点到u点的最短距离是多少. 题解: 这里用的还是边分治的方法. 把所有东西都抠 ...

  7. SPOJ 375. Query on a tree (树链剖分)

    Query on a tree Time Limit: 5000ms Memory Limit: 262144KB   This problem will be judged on SPOJ. Ori ...

  8. SPOJ QTREE Query on a tree 树链剖分+线段树

    题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...

  9. QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树

    Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...

随机推荐

  1. redis订阅者与发布者

    #conding=utf-8 #一.创建redis类 文件名 RedisHelper import redis # conn=redis.Redis(host='127.0.0.1')# import ...

  2. 浅谈设计模式及python实现

    设计模式及Python实现   设计模式是什么? Christopher Alexander:“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样你就能一次又一次地使用 ...

  3. redis过期策略与内存淘汰机制分析

    过期策略: 我们在set key时,可以给一个expire time,就是过期时间 这段过期时间以后,redis对key删除使用:定期删除+惰性删除 定期删除指redis默认在100ms内随机抽取一些 ...

  4. vue面试题整理vuejs基础知识整理

    初级参考 1.v-show 与 v-if 区别 v-show 是css隐藏,v-if是直接销毁和创建,所以频繁切换的适合用v-show 2.计算属性和 watch 的区别 计算属性是自动监听依赖值的变 ...

  5. 如何用Hexo+Github创建自己的技术博客

    注册一个github GitHub官网.按照一般的网站注册登录执行就好了,不详细说. 安装git 安装很简单,一直下一步 git安装教程 很多教程里都说要配置环境变量,我本人安装过5次左右的git,一 ...

  6. 容易上手搭建vue2.0开发环境

    第一步:安装node 前端开发框架和环境都是需要 Node.js ,先安装node.js开发环境,vue的运行是要依赖于node的npm的管理工具来实现,下载https://nodejs.org/en ...

  7. 8.12 day31 进程间通信 Queue队列使用 生产者消费者模型 线程理论 创建及对象属性方法 线程互斥锁 守护线程

    进程补充 进程通信 要想实现进程间通信,可以用管道或者队列 队列比管道更好用(队列自带管道和锁) 管道和队列的共同特点:数据只有一份,取完就没了 无法重复获取用一份数据 队列特点:先进先出 堆栈特点: ...

  8. C/C++ 数据类型

    C/C++ 数据类型 C语言包含5个基本数据类型: void, integer, float, double, 和 char. 类型 描述 字节数 取值范围 void 空类型 1 int 整型 4 - ...

  9. PostgreSQL创建扩展出错

    问题: loraserver_as=# create extension pg_trgm; ERROR: could not open extension control file "/us ...

  10. 小白学Python(5)——python-pptx简单应用

    python-pptx允许您创建新的演示文稿以及对现有演示文稿进行更改. 实际上,它只允许您对现有演示文稿进行更改:只是,如果您从一个没有幻灯片的演示文稿开始,一开始感觉就像是从头开始创建一个幻灯片. ...