【题解】Luogu P5327 [ZJOI2019]语言
原题传送门
看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外
先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[lca(x,y)]\)的线段树上\(x,y\)两位置打\(-2\)标记
线段树中该维护三个东西:
1.dfs序最小的\(lp\)
2.dfs序最大的\(rp\)
3.线段树中所有被打标机的点到根节点路径的并的节点个数\(sum\)
我们进行搜索并从下向上的进行线段树合并,对于每个节点,对答案的贡献就是该节点线段树的根节点的\(sum-dep[lca(lp,rp)]+1-1\)(珂以画图理解一下)
交上去,发现wa了,因为每条路径的贡献被我们算了\(2\)次,所以除以2即可
#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int n,m;
ll ans;
struct edge{
int to,next;
}e[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int size[N],fa[N],son[N],dep[N],top[N],dfn[N],tim,idfn[N];
inline void dfs1(register int x)
{
size[x]=1;
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa[x])
continue;
dep[v]=dep[x]+1;
fa[v]=x;
dfs1(v);
size[x]+=size[v];
if(size[v]>size[son[x]])
son[x]=v;
}
}
inline void dfs2(register int x,register int t)
{
dfn[x]=++tim;
idfn[tim]=x;
top[x]=t;
if(son[x])
dfs2(son[x],t);
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[x]&&v!=son[x])
dfs2(v,v);
}
}
inline int getlca(register int x,register int y)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]<dep[fy])
{
x^=y^=x^=y;
fx^=fy^=fx^=fy;
}
x=fa[fx];
fx=top[x];
}
return dep[x]<dep[y]?x:y;
}
int root[N],tot;
struct node{
int ls,rs,cnt,lp,rp,sum;
}tr[N*60];
inline void pushup(register int x)
{
tr[x].lp=tr[tr[x].ls].lp?tr[tr[x].ls].lp:tr[tr[x].rs].lp;
tr[x].rp=tr[tr[x].rs].rp?tr[tr[x].rs].rp:tr[tr[x].ls].rp;
tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
if(tr[tr[x].ls].rp&&tr[tr[x].rs].lp)
tr[x].sum-=dep[getlca(tr[tr[x].ls].rp,tr[tr[x].rs].lp)];
}
inline void modify(register int &x,register int l,register int r,register int pos,register int val)
{
if(!x)
x=++tot;
if(l==r)
{
tr[x].cnt+=val;
if(tr[x].cnt)
tr[x].lp=tr[x].rp=pos,tr[x].sum=dep[pos];
else
tr[x].lp=tr[x].rp=tr[x].sum=0;
return;
}
int mid=l+r>>1;
if(dfn[pos]<=mid)
modify(tr[x].ls,l,mid,pos,val);
else
modify(tr[x].rs,mid+1,r,pos,val);
pushup(x);
}
inline void merge(register int &a,register int b,register int l,register int r)
{
if(!a||!b)
{
a=a+b;
return;
}
if(l==r)
{
tr[a].cnt+=tr[b].cnt;
if(tr[a].cnt)
tr[a].lp=tr[a].rp=idfn[l],tr[a].sum=dep[idfn[l]];
else
tr[a].lp=tr[a].rp=tr[a].sum=0;
return;
}
int mid=l+r>>1;
merge(tr[a].ls,tr[b].ls,l,mid);
merge(tr[a].rs,tr[b].rs,mid+1,r);
pushup(a);
}
inline void dfs(register int x)
{
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa[x])
continue;
dfs(v);
merge(root[x],root[v],1,tim);
}
if(tr[root[x]].lp&&tr[root[x]].rp)
ans+=tr[root[x]].sum-dep[getlca(tr[root[x]].lp,tr[root[x]].rp)];
}
int main()
{
n=read(),m=read();
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,0);
for(register int i=1;i<=m;++i)
{
int x=read(),y=read();
int lca=getlca(x,y);
modify(root[x],1,tim,x,1);
modify(root[x],1,tim,y,1);
modify(root[y],1,tim,x,1);
modify(root[y],1,tim,y,1);
if(lca>1)
{
modify(root[fa[lca]],1,tim,x,-2);
modify(root[fa[lca]],1,tim,y,-2);
}
}
dfs(1);
write(ans>>1);
return 0;
}
【题解】Luogu P5327 [ZJOI2019]语言的更多相关文章
- Luogu P5327 [ZJOI2019]语言
ZJOI2019Day2的温暖题,然后考场上只会大常数的\(O(n\log^3 n)\),就懒得写拿了60pts走人 首先我们简化题意,容易发现每个点能到达的点形成了一个联通块,我们只需要统计出这个联 ...
- 题解 P5327 [ZJOI2019]语言
P5327 [ZJOI2019]语言 解题思路 暴力 首先讲一下我垃圾的 40pts 的暴力(其他 dalao 都是 60pts 起步): 当然评测机快的话(比如 LOJ 的),可以卡过 3,4 个点 ...
- P5327 [ZJOI2019]语言
一边写草稿一边做题吧.要看题解的往下翻,或者是旁边的导航跳一下. 草稿 因为可以开展贸易活动的条件是存在一种通用语 \(L\) 满足 \(u_i\) 到 \(v_i\) 的最短路径上都会 \(L\) ...
- [题解] Luogu P5446 [THUPC2018]绿绿和串串
[题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...
- 【题解】Luogu P5279 [ZJOI2019]麻将
原题传送门 希望这题不会让你对麻将的热爱消失殆尽 我们珂以统计每种牌出现的次数,不需要统计是第几张牌 判一副牌能不能和,类似这道题 对于这题: 设\(f[i][j][k][0/1]\)表示前\(i\) ...
- 【题解】Luogu P5328 [ZJOI2019]浙江省选
原题传送门 看起来挺妙实际很暴力的一题 已知每个选手的分数都是平面上的直线 题目实际就是让我们求每条直线在整点处最大是第几大 我们考虑先对所有的直线进行半平面交(因为\(a_i\)都是正整数,所以比普 ...
- 题解 [ZJOI2019]语言
题目传送门 题目大意 给出一个 \(n\) 个点的树,现在有 \(m\) 次操作,每次可以选择一个链 \(s,t\),,然后这条链上每个点都会增加一个相同属性,问对于每一个点有与它相同属性的有多少个点 ...
- 题解 Luogu P2499: [SDOI2012]象棋
关于这道题, 我们可以发现移动顺序不会改变答案, 具体来说, 我们有以下引理成立: 对于一个移动过程中的任意一个移动, 若其到达的位置上有一个棋子, 则该方案要么不能将所有棋子移动到最终位置, 要么可 ...
- Luogu P5279 [ZJOI2019]麻将
ZJOI2019神题,间接送我退役的神题233 考场上由于T2写挂去写爆搜的时候已经没多少时间了,所以就写挂了233 这里不多废话直接开始讲正解吧,我们把算法分成两部分 1.建一个"胡牌自动 ...
随机推荐
- c# 读数据库二进制流到图片
public Bitmap PictureShow(string connectionString, string opName, string productType) { ...
- MySQL事务优化
====================事务特性 事务隔离级别 事务控制语句 MySQL优化==================== 事务的概念 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全 ...
- 201871010107-公海瑜《面向对象程序设计(java)》第二周学习总结
201871010107-公海瑜<面向对象程序设计(java)>第二周学习总结 项目 内容 这个作业属于哪个课 ...
- Nacos 学习资料
资料 网址 官方网站 https://nacos.io/zh-cn/docs/what-is-nacos.html github https://github.com/alibaba/nacos 程序 ...
- STM32F10x之NVIC
转载自:https://www.jianshu.com/p/3aa5997fe794 1 异常类型 Cortex-M3内核具有强大的异常响应系统,它把能够打断当前代码执行流程的事件分为异常(excep ...
- Linux中的关机操作
shutdown -h now //马上停止服务进行关机 shutdown -h 12:00 .//在12点后进行关机 shutdown -h +10 //在10分钟后进行关机 shutdown ...
- Python进阶-II 参数陷阱、命名空间、嵌套、作用域、闭包
一.参数陷阱 在使用默认参数时,可能碰见下列情况 def show_args_trap(i, li = []): li.append(100) li[i] = 101 print(li) show_a ...
- ORA-00923: FROM keyword not found where expected
网上搜索这类错误还是挺多的,只提供我遇到的一种情景. 本地数据库环境:Oracle10g 导入别人的项目后,有一段SQL查询总是报如下错误信息: Cause: java.sql.SQLExceptio ...
- 知识点5 C++保存txt文件
简单示例 #include <windows.h> #include <fstream> #include <iostream> #include <stri ...
- 提高 Visualforce 页面加载效率的小知识
一般原则 在设计页面时,我们要将页面的功能降至最少,不要包含多余的功能和数据,以最大化提高运行效率 如果需要开发的功能可以通过 Salesforce 的标准功能实现,那么尽量使用标准功能,比如 工作流 ...