题目链接: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.4184.shallot(线段树分治 线性基)

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

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

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

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

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

  4. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  5. LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset

    题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...

  6. 时空旅行[线段树分治][维护凸壳]

    文章目录 前言 题目 思路 代码 前言 肝了一上午-这是我才学线段树分治的例题-真舒服 题目 温馨提示:首先在UOJ做,LOJ挖数据,BZOJ终极评测... UOJ198 二手剽- 思路 为什么不能用 ...

  7. 线段树分治 ---- F. Extending Set of Points(线段树分治 + 可撤销并查集)

    题目链接 题目大意: 你有个点集合SSS,每次往集合里面加点或者删点(如果要加的点出现过),如果(x1,y1),(x2,y1),(x1,y2),(x2,y2)(x1,y1),(x2,y1),(x1,y ...

  8. 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解

    题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...

  9. POJ 1741 树分治

    题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典 ...

最新文章

  1. python编程基础是什么-Python面向对象编程基础解析(一)
  2. find指定具体时间参数-newermt
  3. java设计模式之委派模式
  4. 没有活动混音器设备可用的解决方法
  5. html设置标签上下居中,html 标签内部元素上下居中
  6. MySql的存储过程
  7. 《算法导论》学习笔记——快速排序
  8. (键盘)代码 19:由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备 解决方法...
  9. MacBook 显示未连接任何摄影机,视频镜头不能用怎么办?
  10. go语言链接show_api,读取网络成语
  11. unity中计算不规则模型的体积与表面积—三角面片与四面体
  12. linux qt 字体哪个好,QT的的字体使用(全局自带字体特别好用)
  13. Mybatis注解开发出现Type interface Mapper.StudentMapper is not known to the MapperRegistry异常解决办法
  14. 用微信小程序实现视频通话
  15. 人民大学:2016经济将深度下滑 货币政策应适度宽松
  16. 想找一家好公司入职或者合作?那么这块天眼查GUI版本非常适合你。
  17. 随机字符串解决大问题之腾讯网如何实现手机扫描二维码登录qq功能的
  18. TC358743xbg是一颗将HDMI信号转换成MIPI CSI2的芯片
  19. 《硅谷产品》读书笔记
  20. Hetero-ReID 综述

热门文章

  1. oracle 物理读突然增加的原因_请教一个诡异的物理读比逻辑读还多的问题!!!!
  2. 函数没有“as”子句;假定返回类型为 object。_TypeScript笔记(一)类型amp;接口...
  3. 回到顶部JavaScript实现
  4. webpack常用的三种JS压缩插件
  5. java.sql.SQLException: connection disabled
  6. 三维重建13X:一些算法试题-今日头条AI-Lab
  7. MxNet教程:使用一台机器训练1400万张图片
  8. matplotlib显示中文字体
  9. Unity 2018.3地形功能更新介绍
  10. 互联网通用架构技术----缓存雪崩