题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2566

题意:一棵有边权的树。结点有颜色。每次修改一个点的颜色。求每次修改后所有同色结点的最近距离。

思路:整体是树分治的方法。其实,分治之后,我们可以理解为重构了这棵树,使得最大深度最小。这棵树的每个结点对于每种颜色保存两个值。一个是该种颜色的所有点到该结点的距离,设这些距离中最小的两个值Min1,Min2,那么Min1+Min2可看做是经过当前结点的这种颜色的两个结点的最近距离,另外,还要保存其他孩子中关于这种颜色的最小值。所有这些最小值的最小值和Min1+Min2再取最小值就是以该节点为根的树的这种颜色的最小值。这些最小值用multiset维护。

另外,结点维护所有同种颜色的距离时也用multiset维护。

对于修改操作,设u节点的颜色由c1变为c2,分两步完成,第一步删除u结点的c1,第二步加入u结点的c2。

两种操作类似,都是从当前结点一直向上更新。细节比较多。

multiset直接删除一个值时是将所有这个值都删掉,只删除一个的话要用指针。

const int M=12005;

struct node
{
int v,w,next;
}; node edges[M<<1];
int head[M],eNum; void add(int u,int v,int w)
{
edges[eNum].v=v;
edges[eNum].w=w;
edges[eNum].next=head[u];
head[u]=eNum++;
} int n,m;
int color[M]; int fa[M][20];
int d[M],dep[M]; int visit[M]; queue<int> Q; void init()
{ Q.push(1);
visit[1]=1; while(!Q.empty())
{
int u=Q.front();
Q.pop(); for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
int w=edges[i].w;
if(!visit[v])
{
fa[v][0]=u;
d[v]=d[u]+w;
dep[v]=dep[u]+1;
Q.push(v);
visit[v]=1;
}
}
} for(int i=1;i<20;i++) for(int j=1;j<=n;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
}
} int calLca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int x=dep[u]-dep[v];
for(int i=0;i<20;i++) if(x&(1<<i)) u=fa[u][i];
if(u==v) return u;
for(int i=19;i>=0;i--)
{
if(fa[u][i]&&fa[v][i]&&fa[u][i]!=fa[v][i])
{
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
} int calDis(int u,int v)
{
int lca=calLca(u,v);
return d[u]+d[v]-d[lca]*2;
} int sonNum[M]; int nodeSum; int arr[M],arrNum; void dfs(int u,int pre)
{
arr[++arrNum]=u; nodeSum++;
sonNum[u]=1;
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
if(v!=pre&&!visit[v])
{
dfs(v,u);
sonNum[u]+=sonNum[v];
}
}
} int calCenter(int u)
{
nodeSum=0; arrNum=0;
dfs(u,0);
int ans=u,Min=INF;
for(int i=1;i<=arrNum;i++)
{
int u=arr[i];
int tmp=max(sonNum[u],nodeSum-sonNum[u]);
if(tmp<Min) Min=tmp,ans=u;
}
return ans;
} struct NODE
{
multiset<int> S,p; int getAns()
{
if(p.size()<2) return INF;
int Min1=*p.begin();
multiset<int>::iterator it=p.begin();
it++;
int Min2=*it;
return Min1+Min2;
} void del(int x)
{
p.erase(p.find(x));
}
}; map<int,NODE> mp[M];
map<int,NODE>::iterator it; int inq[M],KK;
int dis[M];
int parent[M]; int DFS(int root)
{
root=calCenter(root);
Q.push(root);
KK++;
inq[root]=KK;
dis[root]=0; while(!Q.empty())
{
int u=Q.front();
Q.pop(); int c=color[u]; if(mp[root].count(c))
{
mp[root][c].p.insert(dis[u]);
}
else
{
NODE tmp;
tmp.p.insert(dis[u]);
mp[root][c]=tmp;
} for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
int w=edges[i].w;
if(!visit[v]&&KK!=inq[v])
{
inq[v]=KK;
dis[v]=dis[u]+w;
Q.push(v);
}
}
} for(it=mp[root].begin();it!=mp[root].end();it++)
{
NODE tmp=it->second;
it->second.S.insert(tmp.getAns());
}
visit[root]=1; for(int i=head[root];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
if(!visit[v])
{
v=DFS(v); for(it=mp[v].begin();it!=mp[v].end();it++)
{
int c=it->first;
int w=*(it->second.S.begin());
mp[root][c].S.insert(w);
}
parent[v]=root;
}
}
return root;
} int root; multiset<int> SS; void Add(int u,int c,int dis)
{
if(mp[u].count(c))
{
mp[u][c].p.insert(dis);
}
else
{
NODE tmp;
tmp.p.insert(dis);
mp[u][c]=tmp;
}
} int st[M],stTop; void setDel(multiset<int> &S,int x)
{
multiset<int>::iterator it=S.find(x);
if(it!=S.end()) S.erase(it);
} void del(int u,int c)
{
setDel(SS,*mp[root][c].S.begin()); int curNode=u; stTop=0;
while(curNode) st[++stTop]=curNode,curNode=parent[curNode]; for(int i=stTop;i>1;i--)
{
int u=st[i];
int v=st[i-1];
setDel(mp[u][c].S,*mp[v][c].S.begin());
}
curNode=u;
while(curNode)
{
int p=parent[curNode]; setDel(mp[curNode][c].S,mp[curNode][c].getAns());
mp[curNode][c].del(calDis(u,curNode));
mp[curNode][c].S.insert(mp[curNode][c].getAns()); if(p)
{
mp[p][c].S.insert(*(mp[curNode][c].S.begin()));
}
curNode=p;
}
SS.insert(*mp[root][c].S.begin());
} void upd(int u,int c)
{
if(mp[root].count(c))
{
setDel(SS,*mp[root][c].S.begin());
}
int curNode=u;
stTop=0;
while(curNode) st[++stTop]=curNode,curNode=parent[curNode]; for(int i=stTop;i>1;i--)
{
int u=st[i];
int v=st[i-1];
if(!mp[v].count(c)) break;
setDel(mp[u][c].S,*mp[v][c].S.begin());
}
for(int i=1;i<=stTop;i++)
{
int u=st[i];
if(mp[u].count(c))
{
setDel(mp[u][c].S,mp[u][c].getAns());
}
} curNode=u;
while(curNode)
{
Add(curNode,c,calDis(u,curNode));
mp[curNode][c].S.insert(mp[curNode][c].getAns()); int p=parent[curNode];
if(p)
{
mp[p][c].S.insert(*(mp[curNode][c].S.begin()));
}
curNode=p;
}
SS.insert(*mp[root][c].S.begin());
} void change(int u,int c)
{
if(color[u]==c) return;
del(u,color[u]);
upd(u,c); color[u]=c;
} int main()
{
n=myInt();
for(int i=1;i<=n;i++) color[i]=myInt();
clr(head,-1);
for(int i=1;i<n;i++)
{
int u=myInt();
int v=myInt();
int w=myInt();
add(u,v,w);
add(v,u,w);
}
init();
clr(visit,0); root=DFS(1); for(it=mp[root].begin();it!=mp[root].end();it++)
{
SS.insert(*(it->second.S.begin()));
}
int minDis=*SS.begin(); printf("%d\n",minDis==INF?-1:minDis); m=myInt();
while(m--)
{
int x=myInt();
int y=myInt();
change(x,y); minDis=*SS.begin();
printf("%d\n",minDis==INF?-1:minDis);
}
}

  

BZOJ 2566 xmastree(树分治+multiset)的更多相关文章

  1. BZOJ 2599 Race(树分治)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2599 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 题意:每次 ...

  2. BZOJ.4184.shallot(线段树分治 线性基)

    BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...

  3. BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)

    BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...

  4. [BZOJ 4025]二分图(线段树分治+带边权并查集)

    [BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...

  5. BZOJ 2152: 聪聪可可 树分治

    2152: 聪聪可可 Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一 ...

  6. bzoj 4137 [FJOI2015]火星商店问题——线段树分治+可持久化01trie树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4137 关于可持久化01trie树:https://www.cnblogs.com/LadyL ...

  7. bzoj 4025 二分图——线段树分治+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...

  8. BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)

    传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...

  9. 【BZOJ4025】 二分图(线段树分治)

    传送门 BZOJ Solution 只是为了学习一下线段树分治的啦! 当你学会线段树分治之后,可以跳过下面的一部分: 按照时间搞一颗线段树出来,把包含这段区间的操作用vector压进去. 每一个线段树 ...

随机推荐

  1. sql 表连接 join

    inner join  和  join  的 区别 inner join 是内连接 ,查询出两边 都有的数据 join  是交叉 连接, 假设集合A={a, b},集合B={0, 1, 2},则两个集 ...

  2. java父类转子类的一个方法

    一般子类可以转父类.但父类转子类就会报cast error. 使用jsonobject 思想:先把父类转jsonstring 再把jsonstring转子类.剩余的子类值可以设定进去. import ...

  3. JSP-07-使用JavaBean封装数据

    7.1 常命包名 Dao 包中的接口(NewsDao)以及类(NewsDaoImpl)注意负责和数据操作相关的事情. Service 包中的接口和类对dao的方法进行封装和调用,注意负责和业务逻辑相关 ...

  4. java 网络编程(五)----TCP进阶篇上传文本文件

    设计需求:从客户端上传txt文件到服务器,服务端收到文件后,发送消息给客户端接收完成. 1. 服务器端: public class UpLoadFileServer { public static v ...

  5. Android SDK Manager更新报错

    错误log: Fetching https://dl-ssl.google.com/android/repository/addons_list-.xml Fetched Add-ons List s ...

  6. SqlServer 在创建数据库时候指定的初始数据库大小是不能被收缩的

    当你在SqlServer创建数据库的时候可以指定数据库文件的初始大小,比如下图中我们将新创建的数据库MyDB的大小设置成了1024MB 那么你建好的数据库的确也就会占用1024MB左右的磁盘空间 不过 ...

  7. 使用Application Loader打包上传AppStore流程

    配置完你的证书,Bundle Identifier 和描述文件的配置 然后配置工程打开你项目工程 第一步,这里不能选择模拟器,选择iOS Device 如果不支持横屏,把这2个勾去掉 然后查看版本号和 ...

  8. webpack笔记_(2)_Refusing to install webpack as a dependency of itself

    安装webpack时,出现以下问题: Refusing to install webpack as a dependency of itself npm ERR! Windows_NT npm ERR ...

  9. jmeter使用笔记

    接口测试 http协议 接口分成两类,一类是查询功能的接口,一类是保存数据功能的接口. 保存逻辑:数据传入进来,验证通过.保存到数据表中 使用jmeter接口测试的步骤 1.首先添加线程组. 2.配置 ...

  10. CSS3 功能

    1.  CSS3在css2的基础上增加了很多功能,ie8以下的浏览器有可能不支持某些属性,增加了很多圆角.渐变.旋转.阴影等效果 2.  文本修饰 text-decoration 属性用来设置或删除文 ...