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压进去. 每一个线段树 ...
随机推荐
- 【RoR win32】新rails运行后0.0.0.0:3000不能访问
在浏览器中使用127.0.0.1:3000来访问
- tr DEMO
测试数据: [weblogic@etp-mall-dev7][/tmp]$ cat msn.txt aaa bbb bbb ccc ccc ddd bbb eee aaa ccc bbb sss 转换 ...
- Hibernate,JPA注解@ManyToMany_JoinTable
可以通过@ManyToMany注解可定义的多对多关联.同时,也需要通过注解@JoinTable描述关联表和关联条件.如果是双向关联,其中一段必须定义为owner,另一端必须定义为inverse(在对关 ...
- 新增PHP经典笔记
[设置编码] header("Content-type: text/html; charset=utf-8"); 1. parse_url - 解析 URL,返回其组成部分 $ua ...
- 【PHP设计模式 04_GongChang.php】 工厂方法
<?php /** * [工厂方法] * 之前 03.php 简单工厂,如果再增加一个oracle客户端,就需要再次修改服务端Factory的代码. * 在面向对象设计法则中,有一个重要的[开闭 ...
- node-webkit教程<>Native UI API 之Menu(菜单)
node-webkit教程(6)Native UI API 之Menu(菜单)1 前言... 2 6.1 Menu 概述... 3 6.2 menu api6 6.2.1 new Menu([o ...
- C#Winform常引用的库
1.DevExpress:引用其下的不同DLL,可操作使用不同的控件 2.IrisSkin2:引用对应的DLL后,代码如下 private Sunisoft.IrisSkin.SkinEngine s ...
- recycleview中使用checkbox导致的重复选中问题
参考博文:http://www.myexception.cn/mobile/1852852.html 在使用RecycleView做仿微信图片选择器,其中条目中使用了checkbox,在选中时由于ho ...
- ACM题目————吝啬的国度
描述 在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市,他有张该国地图,他想知道如果自己要去参观第T号城市,必须经过的前一个城市是几号城市(假设 ...
- 求两个数的最大公约数(Java)
获得两个随机数(100以内),并放入数组中 public int[] getTwoRandom(){ int[] t = new int[2]; Random rand = new Random(); ...