首页 > 其他分享 >【题解】P5327 [ZJOI2019] 语言

【题解】P5327 [ZJOI2019] 语言

时间:2023-04-21 11:36:45浏览次数:57  
标签:P5327 rt le 10 int 题解 tr dfn ZJOI2019

P5327 [ZJOI2019] 语言

题目描述

九条可怜是一个喜欢规律的女孩子。按照规律,第二题应该是一道和数据结构有关的题。

在一个遥远的国度,有 \(n\) 个城市。城市之间有 \(n - 1\) 条双向道路,这些道路保证了任何两个城市之间都能直接或者间接地到达。

在上古时代,这 \(n\) 个城市之间处于战争状态。在高度闭塞的环境中,每个城市都发展出了自己的语言。而在王国统一之后,语言不通给王国的发展带来了极大的阻碍。为了改善这种情况,国王下令设计了 \(m\) 种通用语,并进行了 \(m\) 次语言统一工作。在第 \(i\) 次统一工作中,一名大臣从城市 \(s_i\) 出发,沿着最短的路径走到了 \(t_i\),教会了沿途所有城市(包括 \(s_i, t_i\))使用第 \(i\) 个通用语。

一旦有了共通的语言,那么城市之间就可以开展贸易活动了。两个城市 \(u_i, v_i\) 之间可以开展贸易活动当且仅当存在一种通用语 \(L\) 满足 \(u_i\) 到 \(v_i\) 最短路上的所有城市(包括 \(u_i, v_i\)),都会使用 \(L\)。

为了衡量语言统一工作的效果,国王想让你计算有多少对城市 \((u, v)\)(\(u < v\)),他们之间可以开展贸易活动。

测试点 \(n\) \(m\) 其他约定
\(1,2\) \(\le 300\) \(\le 300\)
\(3,4\) \(\le 5\times 10^3\) \(\le 5\times 10^3\)
\(5,6\) \(\le 10^5\) \(\le 10^5\) \(y_i=x_i+1\)
\(7\sim 10\) \(\le 10^5\) \(\le 10^5\)

对于 \(100\%\) 的数据,有 \(1 \le x_i, y_i, s_i, t_i \le n\leq 10 ^ 5\),\(1\leq m\leq 10 ^ 5\),\(x_i\neq y_i\)。

题解

线段树合并喵喵题。
考虑对于每个点维护经过它的路径端点的集合,那么当前点能到达的点即为集合内的点构成的虚数的大小。
可以用树上差分,在端点处加入点,lca处减去点。
虚树大小即为在dfs序上设当前点为 u ,前一个点为 v,则虚树大小即为 \(\sum dep_u-dep_{lca(u,v)}\),于是可以线段树下标为dfs序动态维护虚树,差分就将子节点的线段树合并到自己,最终答案除二($ u< v$)即可。
题目的转化非常的妙,将链信息转化为点信息,还有线段树dfs序维护虚树的方法。
然后是线段树合并的总复杂度是 \(n \log n\)的。
代码1h,调了2h,还是太菜了啊。

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=100010;
int head[N],to[N*2],fro[N*2],tail;
int n,m,ansn[N];
long long ans;
int fr[N],dfn[N],bel[N],siz[N],dep[N],dfn_cnt;
struct Lca{
	int dfn[N*2],bel[N],st[N*2][21],cnt,tw[N*2];
	inline int cmp(int x,int y){return (dep[x]<dep[y])?x:y;}
	void init(){
		for(int i=2;i<=cnt;i++)tw[i]=((1<<(tw[i-1]+1))==i)?tw[i-1]+1:tw[i-1];
		for(int i=1;i<=cnt;i++)st[i][0]=dfn[i];
		for(int k=1;k<=20;k++){
			for(int i=1;i+(1<<k)-1<=cnt;i++)st[i][k]=cmp(st[i][k-1],st[i+(1<<(k-1))][k-1]);
		}
		return ;
	}
	int get(int x,int y){
		x=bel[x],y=bel[y];
		if(x>y)swap(x,y);
		int k=tw[y-x+1];
		return cmp(st[x][k],st[y-(1<<k)+1][k]);
	}
}lca;
inline void adlin(int x,int y){
	to[++tail]=y,fro[tail]=head[x],head[x]=tail;
	return ;
}
void dfs(int u,int fa){
	fr[u]=fa;
	dep[u]=dep[fa]+1,bel[u]=++dfn_cnt,dfn[dfn_cnt]=u,siz[u]=1;
	lca.bel[u]=++lca.cnt,lca.dfn[lca.cnt]=u;
	for(int k=head[u];k;k=fro[k]){
		int x=to[k];
		if(x==fa)continue;
		dfs(x,u);
		siz[u]+=siz[x];
		lca.dfn[++lca.cnt]=u;
	}
	return ;
}
int rt[N],ls[N*100],rs[N*100],sum[N*100],cnt;
struct node{
	int l,r,sum;
}tr[N*100];
node operator +(node a,node b){
	node c;
	c.sum=a.sum+b.sum;
	c.l=a.l?a.l:b.l,c.r=b.r?b.r:a.r;
	if(a.r&&b.l)c.sum-=dep[lca.get(a.r,b.l)];
	return c;
}
void update(int u){
	tr[u]=tr[ls[u]]+tr[rs[u]];
	sum[u]=sum[ls[u]]+sum[rs[u]];
	return ;
}
void modify(int &u,int l,int r,int aim,int k){
	if(!u)u=++cnt;
	if(l==r){
		sum[u]+=k;
		if(sum[u]>0)tr[u]=(node){dfn[aim],dfn[aim],dep[dfn[aim]]};
		else tr[u]=(node){0,0,0};
		return ;
	}
	int mid=(l+r)/2;
	if(aim<=mid)modify(ls[u],l,mid,aim,k);
	else modify(rs[u],mid+1,r,aim,k);
	update(u);
	return ;
}
void merge(int &u,int a,int b,int l,int r){
	if(!a||!b)return u=a+b,void(0);
	u=a;
	if(l==r){
		sum[u]+=sum[b];
		if(sum[u]>0)tr[u]=(node){dfn[l],dfn[l],dep[dfn[l]]};
		else tr[u]=(node){0,0,0};
		return ;
	}
	int mid=(l+r)/2;
	merge(ls[u],ls[a],ls[b],l,mid);
	merge(rs[u],rs[a],rs[b],mid+1,r);
	update(u);
	return ; 
}
vector<int>del[N];
void work(int u,int fa){
	for(int k=head[u];k;k=fro[k]){
		int x=to[k];
		if(x==fa)continue;
		work(x,u);
	}
	for(int k=head[u];k;k=fro[k]){
		int x=to[k];
		if(x==fa)continue;
		merge(rt[u],rt[u],rt[x],1,n);
	}
	for(int nw:del[u])modify(rt[u],1,n,bel[nw],-1);
//	modify(rt[u],1,n,bel[u],1);
//	ans+=tr[rt[u]].sum-dep[fr[lca.get(tr[rt[u]].l,tr[rt[u]].r)]]-1;
	ansn[u]=max(0,tr[rt[u]].sum-dep[fr[lca.get(tr[rt[u]].l,tr[rt[u]].r)]]-1);
	ans+=ansn[u];
//	cout<<u<<":"<<tr[rt[u]].sum-dep[fr[lca.get((tr[rt[u]].l),(tr[rt[u]].r))]]<<"-"<<tr[rt[u]].l<<" "<<tr[rt[u]].r<<"\n";
//	modify(rt[u],1,n,bel[u],-1);
//	if(u==1)return ;
//	merge(rt[fa],rt[fa],rt[u],1,n);
	return ;
}
signed main(){
//	freopen("language1.in","r",stdin);
//	freopen("ans.out","w",stdout);
	n=rd(),m=rd();
	for(int i=1;i<n;i++){
		int x=rd(),y=rd();
		adlin(x,y),adlin(y,x);
	}
	dfs(1,0),lca.init();
	for(int i=1;i<=m;i++){
		int s=rd(),t=rd(),x=lca.get(s,t);
//		cout<<s<<" "<<t<<"-"<<x<<"\n";
		modify(rt[s],1,n,bel[s],1),modify(rt[s],1,n,bel[t],1);
//		cout<<s<<":"<<tr[rt[s]].sum<<"-"<<tr[rt[s]].l<<" "<<tr[rt[s]].r<<"\n"; 
		modify(rt[t],1,n,bel[t],1),modify(rt[t],1,n,bel[s],1);
		del[x].push_back(t),del[x].push_back(s);
//		modify(rt[x],1,n,bel[s],-1),modify(rt[x],1,n,bel[t],-1);
		if(x!=1)del[fr[x]].push_back(t),del[fr[x]].push_back(s);
//		if(x!=1)modify(rt[fr[x]],1,n,bel[fr[s]],-1),modify(rt[fr[x]],1,n,bel[fr[t]],-1);
	}
	work(1,0);
	printf("%lld\n",ans/2);
//	for(int i=1;i<=n;i++)cout<<i<<":"<<ansn[i]<<"\n";
	return 0;
}

标签:P5327,rt,le,10,int,题解,tr,dfn,ZJOI2019
From: https://www.cnblogs.com/flywatre/p/17339762.html

相关文章

  • Android问题解决:android.os.FileUriExposedException: file:///storage/......Intent.
    文章目录一、遇到问题二、解决问题三、分析问题一、遇到问题---------beginningofcrash2022-12-2720:18:15.01014422-14422/com.lisi.evidence_boxE/AndroidRuntime:FATALEXCEPTION:mainProcess:com.lisi.evidence_box,PID:14422android.os.FileUriExpose......
  • 2022年中国大学生程序设计竞赛女生专场-比赛题解
    比赛链接:Dashboard-2022年中国大学生程序设计竞赛女生专场-CodeforcesA.减肥计划(模拟)模拟,如果队列第一个人体重是最大的了,则这个人的位置不会再变,直接输出即可。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_......
  • CF1797E 线段树 + 倍增 题解
    Preface有趣的一道ds,赛后不看题解做出来了。Solution首先有一个性质:\(\varphi(x)\)经过\(\mathcal{O}(\logx)\)次迭代后变为\(1\)。证明:若\(x\)为奇数,\(\varphi(x)=x\sum_{i=1}^{k}\frac{p_i-1}{p_i}\),\(p_i\)为奇数,所以\(p_i-1\)为偶数,我们就能得到\(\varphi(x)......
  • LeetCode-Go:一个使用 Go 语言题解 LeetCode 的开源项目
    在中国的IT环境里,大多数场景下,学习算法的目的在于通过笔试算法题。但算法书林林总总,有时候乱花渐欲迷人眼。杜甫有诗云:读书破万卷,下笔如有神。不管选择哪本书,只要深入学习,分层次,逐层进阶,一定可以将算法攻克。笔者强烈推荐一个Github开源项目LeetCode-Go,你不仅可以把他当做......
  • 2022上半年系统集成项目案例分析真题解析(广东卷)
    2022上半年系统集成项目案例分析真题解析(广东卷)......
  • Vscode 卡顿、CPU 过高问题解决
    原则:非必要不要搞很多Vscode的插件,Vscode本身插件很强大,但是非必要不要使用很多插件。在VSCode扩展市场目前其实存在着不少下载量特别高但是不应该再被使用的扩展,显然官方是不可能直接给你标出来哪些扩展已经被废弃了,哪些有严重bug,纯靠扩展作者自觉。第一步:Ctrl+Shift+P:D......
  • (IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案
    转:(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案 【Maven】理解maven的6大内置属性   ......
  • 力扣题解分享1043.分割数组以得到最大和
    1043.分隔数组以得到最大和题目描述给定一个整数数组arr和一个整数k,将该数组分隔为长度最多为k的一些连续子数组。分隔完成后,每个子数组中的所有值都会变为该子数组中的最大值。返回将数组分隔变换后能够得到的元素最大和。示例input:arr=[1,15,7,9,2,5,10]k=......
  • GYM104081 部分题解
    比赛链接:https://codeforces.com/gym/104081目前就做了8题,里面还有4个水题……水题:ACEG,模拟题意即可,C和E有一些细节。不想写题解了F首先目标是如何将这9个数分组,由于答案一定存在,考虑随机化,固定\(a_1\inS_1\),然后随机一个\(a_i\inS_1\),异或得到\(S_1\)的另一......
  • npm install karma时报错的问题解决
    karma在js自动化测试方面很有名,但是安装的时候出的问题npminstall-gkarma 报错好像是socket.iosocket.io.client依赖时报出的错误 看到网上回复说先装下这个:有人说要先装下这个:npminstall-gnode-gyp 试了下问题没有解决。 又有回复说要装这个:npminstall-gws 装好之......