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压进去. 每一个线段树 ...
随机推荐
- zw版【转发·台湾nvp系列Delphi例程】HALCON InpaintingCt1
zw版[转发·台湾nvp系列Delphi例程]HALCON InpaintingCt1 unit Unit1;interfaceuses Windows, Messages, SysUtils, Va ...
- where 子句和having子句中的区别
1.where 不能放在GROUP BY 后面 2.HAVING 是跟GROUP BY 连在一起用的,放在GROUP BY 后面,此时的作用相当于WHERE 3.WHERE 后面的条件中不能有聚集函数 ...
- 使用JWPlayer在网页中嵌入视频
首发:个人博客,持续更新和纠错 我一直以为在网页中嵌入视频是件复杂的事,一研究才知道原来非常简单. 实际就是在页面中嵌入个控件.社区里已有很多解决方案了.jwplayer是最受欢迎的(之一).控件包括 ...
- android SDK安装容易出错的原因
1.实际上,安卓SDK安装之后,拷贝到其他的机子上面.配置一下环境变量,就可以跑起来的 2.但是拷贝到其他的机子上面临着一个问题就是Eclipse已经配置了的android环境,需要在新的机子上面修改 ...
- 161122、BOM 操作写法示例
浏览器相关信息 // 浏览器信息 navigator.userAgent // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/ ...
- 电影TS、TC、SCR、R5、BD、HD等版本是什么意思
在很多电影下载网站的影片标题中我们都能看到,比如<刺杀希特勒BD版>.<游龙戏凤TS版>等,这些英文缩写都是什么意思呢?都代表什么画质?以下就是各个版本的具体含义: 1.CAM ...
- Linux之sed命令详解
简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...
- Calendar的问题
1. include file is not work now. remove <!-- #include file="Calendar.js" -->, add &l ...
- maven手动安装jar到本地仓库
比如oracle驱动ojdbc5.jar 1,安装MAVEN,并配置系统环境变量 2,将jar文件复制到d: 3,打开cmd窗口,cd到d: 4,执行命令:mvn install:install-fi ...
- React Native 开发笔记
ReactNativeDemo 学习ReactNative开发,搭建ReactNative第一个项目 React Native 开发笔记 1.安装Homebrew $ /usr/bin/ruby -e ...