树分治,对于每个分治结构,维护两棵线段树。

第一棵按dfs序维护所有点到重心的距离,第二棵维护每个分支的最长链。

那么当前结构对答案的贡献就是第二棵线段树的最大值$+$次大值。

对于操作$0$,如果是激活某个点,则直接把它距离$+=inf$,隐藏某个点则是$-=inf$。

对于操作$1$,相当于子树全部加上一个值,进行区间加即可。

时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100010,M=262150,inf=1000000000;
int n,m,i,j,e[N][3],ex[N],active,q[N][3],ans[N],tag[M];
int g[N],v[N<<1],w[N<<1],ok[N<<1],nxt[N<<1],ed,G[N],NXT[N];
int son[N],f[N],all,now;
inline void read(int&a){
char c;bool f=0;a=0;
while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
if(c!='-')a=c-'0';else f=1;
while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
if(f)a=-a;
}
inline void umax(int&a,int b){if(a<b)a=b;}
void build(int x,int a,int b){
tag[x]=-inf;
if(a==b)return;
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void change(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){umax(tag[x],p);return;}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,d,p);
if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
}
void print(int x,int a,int b){
if(a==b){
if(q[a][0]==2){
if(ans[a]==1)puts("Nothing..Nothing!");
else if(ans[a]==2)puts("Only one baby!");
else printf("%d\n",tag[x]);
}
return;
}
int mid=(a+b)>>1;
umax(tag[x<<1],tag[x]);
umax(tag[x<<1|1],tag[x]);
print(x<<1,a,mid),print(x<<1|1,mid+1,b);
}
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;ok[ed]=1;nxt[ed]=g[x];g[x]=ed;}
inline void ADD(int x,int y){NXT[y]=G[x];G[x]=y;}
void findroot(int x,int y){
son[x]=1;f[x]=0;
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y){
findroot(v[i],x);
son[x]+=son[v[i]];
if(son[v[i]]>f[x])f[x]=son[v[i]];
}
if(all-son[x]>f[x])f[x]=all-son[x];
if(f[x]<f[now])now=x;
}
int tmp,cur,edge[N],from[N],vis[N];
int d[N],st[N],en[N],dfn,ST[N],EN[N],cp,pool[N];
namespace Node{
int q[N],v[M],tag[M];
inline void tag1(int x,int p){v[x]+=p;tag[x]+=p;}
inline void pb(int x){if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;}
inline void up(int x){v[x]=max(v[x<<1],v[x<<1|1]);}
void build(int x,int a,int b){
tag[x]=0;
if(a==b){v[x]=q[a];return;}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void add(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){tag1(x,p);return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)add(x<<1,a,mid,c,d,p);
if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
up(x);
}
int ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d)return v[x];
pb(x);
int mid=(a+b)>>1,t=-inf;
if(c<=mid)t=ask(x<<1,a,mid,c,d);
if(d>mid)umax(t,ask(x<<1|1,mid+1,b,c,d));
up(x);
return t;
}
}
namespace Sub{
int q[N],fir[M],sec[M];
inline void up(int x){
if(fir[x<<1]>fir[x<<1|1]){
fir[x]=fir[x<<1];
sec[x]=max(sec[x<<1],fir[x<<1|1]);
}else{
fir[x]=fir[x<<1|1];
sec[x]=max(fir[x<<1],sec[x<<1|1]);
}
}
void build(int x,int a,int b){
if(a==b){fir[x]=q[a];sec[x]=-inf;return;}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void change(int x,int a,int b,int c,int p){
if(a==b){fir[x]=p;return;}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p);
up(x);
}
}
inline void init(int x){
from[x]=cur;
vis[x]=now;
ex[x]=1;
for(int i=G[x];i;i=NXT[i])pool[++cp]=i;
}
void dfs(int x,int y,int z,int dep){
umax(tmp,z);
d[x]=dep;
st[x]=++dfn;
Node::q[dfn]=z;
init(x);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)edge[i>>1]=w[i],dfs(v[i],x,z+w[i],dep+1);
en[x]=dfn;
}
inline void update(int l,int r){
if(l>r)return;
int t=Sub::sec[1];
if(ex[now])umax(t,0);
change(1,1,m,l,r,Sub::fir[1]+t);
}
void solve(int x){
int i;
cur=cp=dfn=d[x]=0;
init(x);
for(i=g[x];i;i=nxt[i])if(ok[i]){
edge[i>>1]=w[i];
cur++;
tmp=-inf;
ST[cur]=dfn+1;
dfs(v[i],x,w[i],1);
EN[cur]=dfn;
Sub::q[cur]=tmp;
}
if(!cur)return;
Node::build(1,1,dfn);
Sub::build(1,1,cur);
sort(pool+1,pool+cp+1);
pool[cp+1]=m+1;
update(1,pool[1]-1);
for(i=1;i<=cp;i++){
int A=q[pool[i]][0],B=q[pool[i]][1],C=q[pool[i]][2];
if(!A){
if(B==now){
ex[now]^=1;
update(pool[i],pool[i+1]-1);
continue;
}
if(ex[B])Node::add(1,1,dfn,st[B],st[B],-inf);
else Node::add(1,1,dfn,st[B],st[B],inf);
Sub::change(1,1,cur,from[B],Node::ask(1,1,dfn,ST[from[B]],EN[from[B]]));
ex[B]^=1;
}else{
if(vis[e[B][0]]!=now||vis[e[B][1]]!=now){
update(pool[i],pool[i+1]-1);
continue;
}
int z=d[e[B][0]]>d[e[B][1]]?e[B][0]:e[B][1];
Node::add(1,1,dfn,st[z],en[z],C-=edge[B]);
Sub::change(1,1,cur,from[z],Node::ask(1,1,dfn,ST[from[z]],EN[from[z]]));
edge[B]+=C;
}
update(pool[i],pool[i+1]-1);
}
for(i=g[x];i;i=nxt[i])if(ok[i]){
ok[i^1]=0;
f[0]=all=son[v[i]];
findroot(v[i],now=0);
solve(now);
}
}
int main(){
read(n);
for(ed=i=1;i<n;i++){
for(j=0;j<3;j++)read(e[i][j]);
add(e[i][0],e[i][1],e[i][2]);
add(e[i][1],e[i][0],e[i][2]);
}
read(m);
for(i=1;i<=n;i++)ex[i]=1;
for(active=n,i=1;i<=m;i++){
read(q[i][0]);
if(q[i][0]<2)read(q[i][1]);
if(q[i][0]==1)read(q[i][2]);
if(!q[i][0]){
if(ex[q[i][1]])active--;else active++;
ex[q[i][1]]^=1;
ADD(q[i][1],i);
}
if(q[i][0]==1)ADD(e[q[i][1]][0],i);
if(q[i][0]==2){
if(active==0)ans[i]=1;
if(active==1)ans[i]=2;
}
}
build(1,1,m);
f[0]=all=n;findroot(1,now=0);solve(now);
print(1,1,m);
return 0;
}

  

BZOJ1841 : 蚂蚁搬家的更多相关文章

  1. 计蒜客模拟赛5 D2T2 蚂蚁搬家

    很久很久以前,有很多蚂蚁部落共同生活在一片祥和的村庄里.但在某一天,村庄里突然出现了一只食蚁兽,蚂蚁们为了保全性命而决定搬家. 然而这个村庄四面环山,想要离开这个村庄必须要从地洞里离开,村子里一共有 ...

  2. 蚂蚁的难题(二)首尾相连数组的最大子数组和(DP)

    蚂蚁的难题(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 下雨了,下雨了,蚂蚁搬家了. 已知有n种食材需要搬走,这些食材从1到n依次排成了一个圈.小蚂蚁对每种食材 ...

  3. NYOJ 745 蚂蚁问题(两)

    蚂蚁的难题(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 下雨了,下雨了.蚂蚁搬家了. 已知有n种食材须要搬走,这些食材从1到n依次排成了一个圈.小蚂蚁对每种 ...

  4. NYOJ 745 蚂蚁的难题(二)

    蚂蚁的难题(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 下雨了,下雨了,蚂蚁搬家了. 已知有n种食材需要搬走,这些食材从1到n依次排成了一个圈.小蚂蚁对每种 ...

  5. Burndown chart

    S型的燃尽图 在一次milestone开发过程中,开发者会持续编辑issue列表,每个issue都有自己的生命周期.燃尽图预期这些issues会被线性的消灭掉,所以从第一天直接到最后一天画个直线表示预 ...

  6. DevExpress 学习使用之 NavBarControl

    TNND,没辙啊,没用过那么高级的玩意儿,暂时也没找到中文的详细帮助,简直就是蚂蚁搬家似的摸索,一点儿点儿来吧. 先是NavBarControl的界面样子,貌似可以通过 PaintStyleKind ...

  7. feilong's blog | 目录

    每次把新博客的链接分享到技术群里,我常常会附带一句:蚂蚁搬家.事实上也确实如此,坚持1篇1篇的把自己做过.思考过.阅读过.使用过的技术和教育相关的知识.方法.随笔.索引记录下来,并持续去改进它们,希望 ...

  8. cp/tar/用c语言编写程序 实现cp命令的效果

    1.cp (拷贝) 已存在文件路径  要拷贝的文件路径 实现cp命令的代码如下: #include <stdio.h> //因为要在命令中得到两个路径,所以要用到main函数的两个参数 i ...

  9. 以应用带动SDN发展(CDN峰会 工信部杨崑)(转)

    以应用带动SDN发展(CDN峰会 工信部杨崑)   SDNAP推荐:这是在亚太全媒体SDN峰会由工信部研究院秘书长杨崑做的关于SDN的一个演讲,本人认为主讲者通过对整 个信息服务体系的精简归纳总结,剥 ...

随机推荐

  1. CocoaPods 安装

    虽然网上关于CocoaPods安装教程多不胜数,但是我在安装的过程中还是出现了很多错误,所以大家可以照下来步骤装一下,我相信会很好用. 前言 在iOS项目中使用第三方类库可以说是非常常见的事,但是要正 ...

  2. json数据类型

    JSON 语法规则 JSON 语法是 JavaScript 对象表示法语法的子集. 数据在名称/值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON 名称/值对 JSON 数据的书写格式是 ...

  3. jQuery - 5.样式操作

    样式操作 1.获取样式 attr("class"), 2.设置样式attr("class","myclass"), 3.追加样式addCla ...

  4. jcaptcha组件小小改造解决Invalid ID, could not validate une

    https://my.oschina.net/chainlong/blog/192014

  5. GitHub 中国区前 100 名到底是什么样的人?

    本文根据Github公开API,抓取了地址显示China的用户,根据粉丝关注做了一个排名,分析前一百名的用户属性,剖析这些活跃在技术社区的牛人到底是何许人也!后续会根据我的一些经验出品<技术人员 ...

  6. go sample - hello world

    入门级别的hello world package mainimport "fmt"func main() { fmt.Println("blibliblbibl!&quo ...

  7. phpcms v9实现wap单页教程

    下面以添加“关于我们”这一单页为例作phpcms V9 wap手机门户添加单页的教程说明: 步骤一:复制phpcms\templates\default\wap下的maps.html,粘贴重命名为ab ...

  8. OpenMesh 删除网格顶点

    OpenMesh 提供了 delete_vertex() 函数来实现从网格中删除顶点,在删除掉顶点的同时,所有与该顶点相连的边也同时被删除. OpenMesh 官方文档 中给的顶点删除函数声明如下: ...

  9. Effective C++ 之 Item 5:了解C++默默编写并调用哪些函数

    Effective C++ chapter 2. 构造 / 析构 / 赋值运算 (Constructors, Destructors, and Assignment Operators) Item 5 ...

  10. Tips for OpenMesh

    OpenMesh 求两点之间的距离 MyMesh::Point p1(1,2,3); MyMesh::Point p2(1,2,5); double d=(p1-p2).length();