题意

给一颗带边权的树,有两种操作

  • \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\)。
  • \(Q~v_i\),询问距\(v_i\)点最远的点的距离。

分析

官方题解做法:动态维护直径,然后再支持询问两个点的距离,后者可以 dfs 序 + lca + 树状数组。动态维护直径可以用点分治(点分树),具体做法是,考虑过分治中心的最长路径,我们只需要查询分别以分治中心的每个儿子为根,所在子树的最长链,从中再找到最长和次长即可,这个星状图可以用 set 维护。每个子树则可以使用 dfs 序+线段树维护。复杂度 O(nlog2n)。

其实我们不用考虑直径,同样维护以分治中心的每个儿子为根,所在子树的最长链,用个可删堆\(ch[x]\)维护\(x\)的每个儿子的子树的最长链,查询距\(v\)点最远的距离时,有两种情况

  • \(v\)点作为分治中心,此时答案为\(ch[v]\)。
  • 跳\(v\)的点分树中的祖先,先将\(ch[fa[v]]\)中包括\(v\)的子树的最长链删去,答案为\(dis(fa[v],v)+ch[fa[v]]\),这个\(dis\)可以用树状数组+\(lca\)+dfs序维护。

所有答案取最大值就是最终答案了。每个子树中的链我是用dfs序+动态开点线段树维护的,细节很多,因为网上没这题点分树做法的博客,自己也刚学,很多处理细节都是自己YY的...写的很繁,感觉只有我能看懂(

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=1e5+10;
typedef pair<int,int> pii;
int n,q;
int sz[maxn],mxp[maxn],vis[maxn],f[maxn],sum,rt;
ll tr[maxn];
int e[maxn];
int id[maxn];
vector<pii>g[maxn];
vector<int>son[maxn];
unordered_map<int,int>in[maxn],out[maxn],pd[maxn];
void add(int x,ll k){
while(x<=n) tr[x]+=k,x+=x&-x;
}
ll dor(int x){
ll ret=0;
while(x) ret+=tr[x],x-=x&-x;
return ret;
}
ll a[maxn*140],tag[maxn*140];
int ls[maxn*140],rs[maxn*140],rtt[maxn],tot;
void pdu(int p,ll k){a[p]+=k,tag[p]+=k;}
void up(int dl,int dr,int l,int r,int &p,ll k){
if(dl>dr||!dl) return;
a[++tot]=a[p],ls[tot]=ls[p],tag[tot]=tag[p],rs[tot]=rs[p],p=tot;
if(l==dl&&r==dr){
a[p]+=k;tag[p]+=k;
return;
}int mid=l+r>>1;
pdu(ls[p],tag[p]);pdu(rs[p],tag[p]);tag[p]=0;
if(dr<=mid) up(dl,dr,l,mid,ls[p],k);
else if(dl>mid) up(dl,dr,mid+1,r,rs[p],k);
else up(dl,mid,l,mid,ls[p],k),up(mid+1,dr,mid+1,r,rs[p],k);
a[p]=max(a[ls[p]],a[rs[p]]);
}
ll qy(int dl,int dr,int l,int r,int p){
if(l==dl&&r==dr) return a[p];
int mid=l+r>>1;
pdu(ls[p],tag[p]);pdu(rs[p],tag[p]);tag[p]=0;
if(dr<=mid) return qy(dl,dr,l,mid,ls[p]);
else if(dl>mid) return qy(dl,dr,mid+1,r,rs[p]);
else return max(qy(dl,mid,l,mid,ls[p]),qy(mid+1,dr,mid+1,r,rs[p]));
}
struct heap {
priority_queue<ll> A, B; // heap=A-B
void insert(ll x) { A.push(x); }
void erase(ll x) { B.push(x); }
ll top() {
while (!B.empty() && A.top() == B.top()) A.pop(), B.pop();
return A.top();
}
void pop() {
while (!B.empty() && A.top() == B.top()) A.pop(), B.pop();
A.pop();
}
ll top2() {
ll t = top(), ret;
pop();
ret = top();
A.push(t);
return ret;
}
int size() { return A.size() - B.size(); }
}ch[maxn];
struct LCA{
int sz[maxn],d[maxn],f[maxn],top[maxn],son[maxn],in[maxn],out[maxn],p[maxn],id[maxn],num;
ll dist[maxn];
void dfs1(int u){
sz[u]=1;d[u]=d[f[u]]+1;
for(pii x:g[u]){
if(x.fi==f[u]) continue;
f[x.fi]=u;dist[x.fi]=dist[u]+e[x.se],id[x.se]=x.fi;
dfs1(x.fi);
sz[u]+=sz[x.fi];
if(sz[x.fi]>sz[son[u]]) son[u]=x.fi;
}
}
void dfs2(int u,int t){
top[u]=t;in[u]=++num;p[num]=u;
if(son[u]) dfs2(son[u],t);
for(pii x:g[u]){
if(x.fi==f[u]||x.fi==son[u]) continue;
dfs2(x.fi,x.fi);
}
out[u]=num;
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x=f[top[x]];
}
if(d[x]<d[y]) swap(x,y);
return y;
}
}L;
ll dis(int x,int y){
return dor(L.in[x])+dor(L.in[y])-2*dor(L.in[L.lca(x,y)]);
}
void getrt(int u,int fa){
sz[u]=1;mxp[u]=0;
for(pii x:g[u]){
if(x.fi==fa||vis[x.fi]) continue;
getrt(x.fi,u);
sz[u]+=sz[x.fi];
mxp[u]=max(mxp[u],sz[x.fi]);
}
mxp[u]=max(mxp[u],sum-sz[u]);
if(mxp[u]<mxp[rt]) rt=u;
}
void calc(int u,int fa,int fart){
son[rt].pb(u);
in[rt][u]=son[rt].size();
if(fart!=-1) up(in[f[rt]][u],in[f[rt]][u],1,son[fart].size(),rtt[rt],dis(fart,u));
for(pii x:g[u]){
if(x.fi==fa||vis[x.fi]) continue;
pd[rt][x.se]=x.fi;id[x.se]=x.fi;
calc(x.fi,u,fart);
}
out[rt][u]=son[rt].size();
}
void solve(int u){
vis[u]=1;
for(pii x:g[u]){
if(vis[x.fi]) continue;
sum=sz[x.fi];mxp[rt=0]=inf;
getrt(x.fi,0);getrt(rt,0);
f[rt]=u;
calc(rt,0,u);
ch[u].insert(a[rtt[rt]]);
solve(rt);
}
ch[u].insert(0);
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d",&n);
for(int i=1,x,y;i<n;i++){
scanf("%d%d%d",&x,&y,&e[i]);
g[x].pb(pii(y,i));g[y].pb(pii(x,i));
}
L.dfs1(1);L.dfs2(1,1);
for(int i=1;i<=n;i++) add(L.in[i],L.dist[i]),add(L.in[i]+1,-L.dist[i]);
sum=mxp[rt]=n;
getrt(1,0);calc(rt,0,-1);solve(rt);
scanf("%d",&q);
while(q--){
char c[2];
int x,j;
ll y;
scanf("%s",c);
if(c[0]=='C'){
scanf("%d%lld",&j,&y);
int gt=L.id[j];
ll ret=e[j];
x=id[j];
add(L.in[gt],y-ret),add(L.out[gt]+1,ret-y);
for(int i=x;f[i];i=f[i]){
ch[f[i]].erase(a[rtt[i]]);
up(in[f[i]][pd[f[i]][j]],out[f[i]][pd[f[i]][j]],1,son[f[i]].size(),rtt[i],y-ret);
ch[f[i]].insert(a[rtt[i]]);
}
e[j]=y;
}else{
scanf("%d",&x);
ll ans=ch[x].top();
for(int i=x;f[i];i=f[i]){
ch[f[i]].erase(a[rtt[i]]);
ans=max(ans,dis(f[i],x)+ch[f[i]].top());
ch[f[i]].insert(a[rtt[i]]);
}
printf("%lld\n",ans);
}
}
return 0;
}

2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树的更多相关文章

  1. 2019ICPC 上海网络赛 G题 Substring(哈希)

    题意: 给了一个母串S, 每次循环给了一个模板串,问模板串在母 串中“匹配”了多少次?“匹配”的意思就是首字母和尾字母一样, 中间字母顺序可以换. 题解: 字符串hash.我们将询问字符串的首尾特殊h ...

  2. 2019ICPC上海网络赛A 边分治+线段树

    题目: 给定一棵树, 带边权. 现在有2种操作: 1.修改第i条边的权值. 2.询问u到其他一个任意点的最大距离是多少. 解法:边分治+线段树 首先我们将所有的点修改和边修改都存在对应的边里面. 然后 ...

  3. 2019ICPC 上海网络赛 L. Digit sum(二维树状数组+区间求和)

    https://nanti.jisuanke.com/t/41422 题目大意: 给出n和b,求1到n,各数在b进制下各位数之和的总和. 直接暴力模拟,TLE.. 没想到是要打表...还是太菜了. # ...

  4. 计蒜客模拟赛 #5 (B 题) 动态点分治+线段树

    虽然是裸的换根dp,但是为了在联赛前锻炼码力,强行上了点分树+线段树. 写完+调完总共花了不到 $50$ 分钟,感觉还行. code: #include <bits/stdc++.h> # ...

  5. 线段树+单调栈+前缀和--2019icpc南昌网络赛I

    线段树+单调栈+前缀和--2019icpc南昌网络赛I Alice has a magic array. She suggests that the value of a interval is eq ...

  6. 2019ICPC南京网络赛A题 The beautiful values of the palace(三维偏序)

    2019ICPC南京网络赛A题 The beautiful values of the palace https://nanti.jisuanke.com/t/41298 Here is a squa ...

  7. 2019 ICPC上海网络赛 A 题 Lightning Routing I (动态维护树的直径)

    题目: 给定一棵树, 带边权. 现在有2种操作: 1.修改第i条边的权值. 2.询问u到其他一个任意点的最大距离是多少. 题解: 树的直径可以通过两次 dfs() 的方法求得.换句话说,到任意点最远的 ...

  8. HDU 5044(2014 ACM-ICPC上海网络赛)

    题意:给定一个树形图,节点10^5,有两种操作,一种是把某两点间路径(路径必定唯一)上所有点的权值增加一个固定值. 另一种也是相同操作,不同的是给边加权值.操作次数10^5.求操作过后,每个点和每条边 ...

  9. hdu 5476 Explore Track of Point(2015上海网络赛)

    题目链接:hdu 5476 今天和队友们搞出3道水题后就一直卡在这儿了,唉,真惨啊……看着被一名一名地挤出晋级名次,确实很不好受,这道恶心的几何题被我们3个搞了3.4个小时,我想到一半时发现样例输出是 ...

随机推荐

  1. 使用 backdoor 工具注入ShellCode

    backdoor-factory 顾名思义,直接翻译过来就是后门工厂的意思.其利用打补丁的方式编码加密PE文件,可以轻松的生成win32PE后门程序,从而帮助我们绕过一些防病毒软件的查杀,达到一定得免 ...

  2. Servlet获取JSP中的汉字乱码问题解决方案

    1.String customerName=request.getParameter("customer_name");这样会出现乱码 解决方案很简单: String custom ...

  3. JSON在JS中的应用

    一. JSON在JS中的应用: 首先解释下JSON对象与普通js对象字面量定义时格式的区别: Js对象字面量定义格式: var person = { name:"Wede", ag ...

  4. 客户端相关知识学习(十)之app给h5传递数据

    方法一: app可以把参数传到h5的链接里,用类似?xx=xx&xx=xx的形式拼接,js解析参数即可. 方法二: 情况一:app调用h5 原生app都可以对js的function进行触发,前 ...

  5. JavaScript笔记(5)

    1.DOM操作 常用的DOM操作 document.getElementById(id); //返回指定id的元素,通用 document.getElementsByTagName(tagName); ...

  6. JS原生实现照片抽奖

    HTML表格标记实现九宫格,放入九张图片.利用CSS的滤镜属性控制图片的透明度.Javascript实现抽奖和中奖. 可以做为教师上课,随机抽取回答问题的同学,使学生感受到随机的公平性,简单有趣! 点 ...

  7. 客户想要的 vs 客户实际预算:漫画解读软件开发模式 ​​​​

    转自:http://blog.jobbole.com/113230/ 1913 年,美利坚工业之神——亨利福特,发明了世界上第一条流水线,汽车工业从此进入了大规模生产的时代.丰田公司提出的丰田生产系统 ...

  8. 微信小程序文章收录

    基础篇 03-04 微信登入小程序与后端实现 - 小猿取经 - 博客园 我做的小程序 - 小y - 博客园 小程序二维码和小程序带参数二维码生成 - Likwo - 博客园 accesstoken 微 ...

  9. Image Processing and Analysis_8_Edge Detection: Optimal edge detection in two-dimensional images ——1996

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  10. 《数字图像处理(MATLAB)》冈萨雷斯

    <数字图像处理(MATLAB)>冈萨雷斯 未完结! 参考:数字图像处理——https://blog.csdn.net/dujing2019/article/category/8820151 ...