BZOJ 2566 xmastree(树分治+multiset)
题目链接: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)的更多相关文章
- BZOJ 2599 Race(树分治)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2599 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 题意:每次 ...
- BZOJ.4184.shallot(线段树分治 线性基)
BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...
- BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)
BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...
- [BZOJ 4025]二分图(线段树分治+带边权并查集)
[BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...
- BZOJ 2152: 聪聪可可 树分治
2152: 聪聪可可 Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一 ...
- bzoj 4137 [FJOI2015]火星商店问题——线段树分治+可持久化01trie树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4137 关于可持久化01trie树:https://www.cnblogs.com/LadyL ...
- bzoj 4025 二分图——线段树分治+LCT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- 【BZOJ4025】 二分图(线段树分治)
传送门 BZOJ Solution 只是为了学习一下线段树分治的啦! 当你学会线段树分治之后,可以跳过下面的一部分: 按照时间搞一颗线段树出来,把包含这段区间的操作用vector压进去. 每一个线段树 ...
随机推荐
- linux系统-代码行数计算
find macc-cometd -type f -name "*.java" -print0 | xargs -0 wc -l
- 夺命雷公狗---node.js---18之项目的构建在node+express+mongo的博客项目3头尾左侧分离法
在实际的开发中我们的项目往往都是需要头尾分离开来的,居然是后台管理界面当然也不能错过这么好的这步.. 首先我们将我们要分离的部分代码先剪切出来,如下所示: 将他们都弄出来... 这部分的内容分别对应的 ...
- 夺命雷公狗---node.js---9实现页面的跳转
废话不多说,我们先来看看项目的文件结构,如下所示: 然后我们创建一个index.js的文件让他来做端口监听,代码如下所示: var http = require('http'); var fs = r ...
- Java :List
1.List是一个接口,不能实例化,需要实例化一个ArrayList或者LinkedListList myList = new ArrayList(); 2.List中可以添加任何对象,包括自己定义的 ...
- iBatis叙述
1.添加Mybatis的配置文件conf.xml 在src目录下创建一个conf.xml文件,如下图所示: 2.定义表所对应的实体类 3.定义操作users表的sql映射文件userMapper.xm ...
- HDU4288:Coder(线段树单点更新版 && 暴力版)
Problem Description In mathematics and computer science, an algorithm describes a set of procedures ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- js获取IP地址方法总结_转
js代码获取IP地址的方法,如何在js中取得客户端的IP地址.原文地址:js获取IP地址的三种方法 http://www.jbxue.com/article/11338.html 1,js取得IP地址 ...
- linux系统修改CST时区
================================================= [root@tzyyserveryg ~]# date -R Fri, 28 Nov 2014 08 ...
- 模拟namenode崩溃,使用secondarynamenode恢复
方法一.使用namespaceID 1.在namenode节点上,将dfs.name.dir指定的目录中(这里是name目录)的内容情况,以此来模拟故障发生. [hadoop@node1 name]$ ...