首页 > 其他分享 >CF1192B/P6845 Dynamic Diameter

CF1192B/P6845 Dynamic Diameter

时间:2024-09-09 16:51:41浏览次数:7  
标签:Diameter int Dynamic dep dfn maxn CF1192B include define

题意

给定一棵带权树和 \(q\) 次询问,每次询问修改一条树边的权值,并查询修改后树的直径。询问之间不独立。

\(n,q\le 10^5\),强制在线。

分析

回想一下,两个点的距离可以被表示成 \(dep_x+dep_y-2dep_{lca(x,y)}\)。

而树的直径,本质上就是求 \(\max_{x,y}dep_x+dep_y-2dep_{lca(x,y)}\)。

发现需要单点修改,于是考虑用个什么数据结构去维护它。

正常的 dfn 序肯定是维护不了这棵树的,我们考虑在树的欧拉序下搞事情。

正常的 dfn 序,是在递归到每个点的开始,给该点打上 dfn 标记。

而欧拉序,同样是在递归到每个点的开始打上标记,而在递归完每一个子树时,再给该点打一个标记。容易发现欧拉序的序列长度是 \(2n-2\)。

我们使用 dfn 序是因为 dfn 序有“子树内的所有点的 dfn 序相邻”的性质,把树拍到序列上用数据结构维护。

而欧拉序也有很好的性质:

  • 两个点的 \(lca\) 在欧拉序上位于在两个点中间。
  • 两个点在欧拉序上的区间内深度最小的点是它们的 \(lca\)。

那我们就相当于要在欧拉序上选三个点 \(x,y,z(x\le y\le z)\),使得 \(dep_x+dep_z-2dep_y\) 最大。由于区间 \([x,z]\) 内深度最小的点是 \(lca\),所以 \(y\) 取不是 \(lca\) 的点一定会使答案变劣。

考虑用线段树维护这个东西,需要维护已经选了 \(x(z),y,xy,yz,xyz\) 的最优答案,注意我们要让 \(dep_y\) 尽可能的小,所以 \(y\) 的标记要维护最小值。

标记的合并类似最大子段和的合并方式。

修改的话,设这条边是 \(fa\rightarrow x\),则修改就相当于对所有 \(x\) 子树内的点深度 \(+delta\),\(delta\) 为这条边边权的变化量。记录每个点在欧拉序上第一次出现位置和最后一次出现位置,对这段区间区间加即可。

时间复杂度 \(O(n\log n)\)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0);
#define OTIE cout.tie(0);
#define FlushIn fread(Fread::ibuf,1,1<<21,stdin)
#define FlushOut fwrite(Fwrite::obuf,1,Fwrite::S-Fwrite::obuf,stdout)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P__ puts("")
#define PU puts("--------------------")
#define popc __builtin_popcount
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define rep(a,b,c) for(int a=(b);a<=(c);a++)
#define per(a,b,c) for(int a=(b);a>=(c);a--)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=d)
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=d)
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) (x&-x)
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mem(x,y) memset(x,y,sizeof x)
//#define double long double
#define int long long
//#define int __int128
using namespace std;
bool greating(int x,int y){return x>y;}
bool greatingll(long long x,long long y){return x>y;}
bool smallingll(long long x,long long y){return x<y;}
namespace Fread {
	const int SIZE=1<<21;
	char ibuf[SIZE],*S,*T;
	inline char getc(){if(S==T){T=(S=ibuf)+fread(ibuf,1,SIZE,stdin);if(S==T)return '\n';}return *S++;}
}
namespace Fwrite{
	const int SIZE=1<<21;
	char obuf[SIZE],*S=obuf,*T=obuf+SIZE;
	inline void flush(){fwrite(obuf,1,S-obuf,stdout);S=obuf;}
	inline void putc(char c){*S++=c;if(S==T)flush();}
	struct NTR{~NTR(){flush();}}ztr;
}
/*#ifdef ONLINE_JUDGE
#define getchar Fread::getc
#define putchar Fwrite::putc
#endif*/
inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}return x*f;
}
inline void write(int x,char ch='\0'){
	if(x<0){x=-x;putchar('-');}
	int y=0;char z[40];
	while(x||!y){z[y++]=x%10+48;x/=10;}
	while(y--)putchar(z[y]);if(ch!='\0')putchar(ch);
}
bool Mbg;
const int maxn=2e5+5,maxm=4e5+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,m,Q,W;
vector<pii>G[maxn];
int uu[maxn],vv[maxn],ww[maxn];
int dep[maxn],dis[maxn],dfn[maxn];
int fst[maxn],lst[maxn];
void dfs(int x,int y){
	fst[x]=lst[x]=++m,dep[x]=dep[y]+1,dfn[m]=x;
	for(pii i:G[x])if(i.fi^y)dis[i.fi]=dis[x]+i.se,dfs(i.fi,x),lst[x]=++m,dfn[m]=x;
}
namespace segtree{
	struct node{
		int mx,mn,lans,rans,ans,tag;
	}d[maxn<<2];
	void pu(int p){
		d[p].mx=max(d[lson(p)].mx,d[rson(p)].mx);
		d[p].mn=min(d[lson(p)].mn,d[rson(p)].mn);
		d[p].lans=max({d[lson(p)].lans,d[rson(p)].lans,d[lson(p)].mx-2*d[rson(p)].mn});
		d[p].rans=max({d[lson(p)].rans,d[rson(p)].rans,d[rson(p)].mx-2*d[lson(p)].mn});
		d[p].ans=max({d[lson(p)].ans,d[rson(p)].ans,d[lson(p)].lans+d[rson(p)].mx,d[lson(p)].mx+d[rson(p)].rans});
	}
	void pt(int p,int v){
		d[p].mx+=v,d[p].mn+=v,d[p].lans-=v,d[p].rans-=v,d[p].tag+=v;
	}
	void pd(int p){
		if(d[p].tag){
			pt(lson(p),d[p].tag),pt(rson(p),d[p].tag);
			d[p].tag=0;
		}
	}
	void bd(int l=1,int r=m,int p=1){
		if(l==r){
			pt(p,dis[dfn[l]]);
//			d[p].mx=d[p].mn=dis[dfn[l]];
			return;
		}
		int mid=l+r>>1;bd(l,mid,lson(p)),bd(mid+1,r,rson(p));
		pu(p);
	}
	void upd(int ll,int rr,int v,int l=1,int r=m,int p=1){
		if(ll<=l&&r<=rr)return pt(p,v);
		int mid=l+r>>1;pd(p);
		if(ll<=mid)upd(ll,rr,v,l,mid,lson(p));
		if(rr>mid)upd(ll,rr,v,mid+1,r,rson(p));
		pu(p);
	}
}using namespace segtree;
void solve_the_problem(){
	n=rd(),Q=rd(),W=rd();
	rep(i,1,n-1){
		uu[i]=rd(),vv[i]=rd(),ww[i]=rd();
		G[uu[i]].pb(vv[i],ww[i]),G[vv[i]].pb(uu[i],ww[i]);
	}
	dfs(1,0);
//	rep(i,1,m)write(dfn[i],32);P__;
//	rep(i,1,n)write(dis[i],32);P__;
	rep(i,1,n-1)if(dep[uu[i]]>dep[vv[i]])swap(uu[i],vv[i]);
	bd(); 
	int lstans=0;
	while(Q--){
		int x=(rd()+lstans)%(n-1)+1,y=(rd()+lstans)%W;
		upd(fst[vv[x]],lst[vv[x]],y-ww[x]),ww[x]=y;
		write(lstans=d[1].ans,10);
	}
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
//	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;while(_--)solve_the_problem();
}
/*

*/

标签:Diameter,int,Dynamic,dep,dfn,maxn,CF1192B,include,define
From: https://www.cnblogs.com/dcytrl/p/18404858

相关文章