树链剖分吼啊

一看就看出是LCT模板题啦

前记

见这么多人写LCT,却很少人写树链剖分,于是我就来一发树链剖分(其实是因为自己不会LCT)

本蒟蒻的写法和诸位写树链剖分的大神有点不同

思路

树链剖分,简单题

操作

操作1:'C' 操作 : 简单的说就是把x到y的边cut掉,题目又保证x,y相邻,肯定直接LCT啦,那么我们就可以将x,y的所以边权加1,表示那些边多了一次战争。

操作2:'U' 操作 : 简单的说就是把之前cut的边加回来,我们只需要记录之前每一次战争的两个部落编号,战争结束就把那两个部落直接的边权减去1就可以了,表示那些边少了一次战争。

操作3:'Q' 操作 : 简单的说就是询问x,y之间的边权和,如果是0,表示经过的边一次战争也没有,就是yes;不然就有战争,是no。

这么一看,思路是不是很简单。

但还有些问题,树链剖分是针对点权的,我们如何转换为边权呢?

点权转边权

方法有很多,例如在每一条边都多加1个点,在加的那个点上记录权值。

但是,这里讲一下我的做法:直接忽略

在一颗树内,点有n个,边有n-1条,所以我们可以让每一条边对应到点上,对应方式就是边的编号是边上两点深度小的点编号。

那么就只会有根是没有边对应的所以我们可以假设有一条编号为根的边和根相连。

将x,y的边权加就等于将x,y的点权全部加,然后LCA(x,y)的点权减回去(可以自己画图尝试一下)

查询x,y的边权和就等于将x,y的点权全部累加,然后减去LCA(x,y)的点权(可以自己画图尝试一下)

于是我们整个思路就出来了(这样就不用改线段树啦>w< )

代码

#include<bits/stdc++.h>
#define maxn 4000001
#define L(x) (x<<1)
#define R(x) ((x<<1)|1)
using namespace std;
int tree[maxn],tag[maxn];
int rev[maxn],dep[maxn],size[maxn],seg[maxn],top[maxn],son[maxn],father[maxn];
int n,m,root,x,y,z,a[maxn],visx[maxn],visy[maxn],tot;
int cnt,from[maxn],to[maxn],Next[maxn],head[maxn];
char mode;
void add(int x,int y){
cnt++;
from[cnt]=x;to[cnt]=y;
Next[cnt]=head[x];head[x]=cnt;
}
//线段树
void pushdown(int node,int begin,int end){
if(tag[node]){
tag[L(node)]+=tag[node];
tag[R(node)]+=tag[node];
int mid=(begin+end)>>1;
tree[L(node)]+=(mid-begin+1)*tag[node];
tree[R(node)]+=(end-mid)*tag[node];
tag[node]=0;
}
}
void update(int node,int begin,int end,int x,int y,int val){
if(begin>y||end<x)return;
if(begin>=x&&end<=y){
tag[node]+=val;
tree[node]+=(end-begin+1)*val;
return;
}else{
pushdown(node,begin,end);
int mid=(begin+end)>>1;
if(x<=mid)update(L(node),begin,mid,x,y,val);
if(y>mid) update(R(node),mid+1,end,x,y,val);
tree[node]=tree[L(node)]+tree[R(node)];
}
}
int query(int node,int begin,int end,int x,int y){
if(begin>y||end<x)return 0;
if(begin>=x&&end<=y){
return tree[node];
}else{
pushdown(node,begin,end);
int mid=(begin+end)>>1,sum=0;
if(x<=mid)sum+=query(L(node),begin,mid,x,y);
if(y>mid) sum+=query(R(node),mid+1,end,x,y);
return sum;
}
}
//线段树
int dfs1(int x){ //树链剖分模板
size[x]=1;
dep[x]=dep[father[x]]+1;
for(int i=head[x];i!=-1;i=Next[i]){
int v=to[i],big=0;
if(father[x]==v)continue;
father[v]=x;
big=dfs1(v);
size[x]+=big;
if(big>size[son[x]])son[x]=v;
}
return size[x];
}
void dfs2(int x){ //树链剖分模板
if(son[x]){
seg[son[x]]=++seg[0];
top[son[x]]=top[x];
rev[seg[0]]=son[x];
dfs2(son[x]);
}
for(int i=head[x];i!=-1;i=Next[i]){
int v=to[i];
if(!top[v]){
seg[v]=++seg[0];
top[v]=v;
rev[seg[0]]=v;
dfs2(v);
}
}
}
void linkadd(int x,int y,int z){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
update(1,1,seg[0],seg[fx],seg[x],z);
x=father[fx];fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
update(1,1,seg[0],seg[x],seg[y],z);
update(1,1,seg[0],seg[x],seg[x],-z); //LCA特殊处理
}
int linkquery(int x,int y){
int fx=top[x],fy=top[y],ans=0;
while(fx!=fy){
if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
ans+=query(1,1,seg[0],seg[fx],seg[x]);
x=father[fx];fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
ans+=query(1,1,seg[0],seg[x],seg[y]);
ans-=query(1,1,seg[0],seg[x],seg[x]); //减LCA
return ans;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);root=1;
for(int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs1(root);
seg[root]=++seg[0];
rev[seg[0]]=root;
top[root]=root;
dfs2(root);
for(int i=1;i<=m;i++){
scanf("%s",&mode);
if(mode=='C'){
scanf("%d%d",&x,&y);
visx[++tot]=x;visy[tot]=y; //记录每一次战争的两个部落
linkadd(x,y,1); //x到y的边权加1
}
if(mode=='U'){
scanf("%d",&x);
linkadd(visx[x],visy[x],-1); //战争结束就减回去
}
if(mode=='Q'){
scanf("%d%d",&x,&y);
int q=linkquery(x,y); //查询x到y的边权和
if(q==0)printf("Yes\n");else //如果q为0就可以
printf("No\n"); //不行就……
}
}
}

另外推荐题目

P3258 [JLOI2014]松鼠的新家 即其题解

题解 P3950 【部落冲突】的更多相关文章

  1. luogu题解 P3950部落冲突--树链剖分

    题目链接 https://www.luogu.org/problemnew/show/P3950 分析 大佬都用LCT,我太弱只会树链剖分 一个很裸的维护边权树链剖分题.按照套路,对于一条边\(< ...

  2. lupgu P3950 部落冲突

    题目链接 luogu P3950 部落冲突 题解 树剖线段树可以 lct还行 代码 #include<cstdio> #include<algorithm> inline in ...

  3. 洛谷 P3950 部落冲突 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例1 输出样例1 输入样例2 输出样例2 输入样例3 输出样例3 说明 思路 AC代码 总结 题面 题目链接 P3 ...

  4. 洛谷P3950 部落冲突 [LCT]

    题目传送门 部落冲突 格式难调,体面就不放了. 分析: julao们应该都看得出来就是个$LCT$板子,战争就$cut$,结束就$link$,询问就$find$.没了... 太久没打$LCT$,然后发 ...

  5. 【luogu P3950 部落冲突】 题解

    题目连接:https://www.luogu.org/problemnew/show/P3950 1.像我这种学数据结构学傻了的 2.边权化点权 所有点权初始化0 3.对于战争 将深度较深的-1,对于 ...

  6. 【题解】Luogu P3950 部落冲突

    原题传送门 这题用Link-Cut-Tree解决,Link-Cut-Tree详解 我们用Link-Cut-Tree维护连通性(十分无脑) 一开始先把树中每条边的两端连接 U操作:把u,v两个点连起来 ...

  7. [题解] 洛谷P3950 部落冲突

    传送门 拿到题目,一看 裸LCT (其实是我懒得打,splay又臭又长) 首先,这道题的意思就是删掉一些边 所以常规操作 点权转边权 之后对于战争操作,在对应的边上+1 对于和平操作,在对应的边上-1 ...

  8. 【刷题】洛谷 P3950 部落冲突

    题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多 ...

  9. P3950 部落冲突

    题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多 ...

  10. 洛谷P3950 部落冲突(LCT)

    洛谷题目传送门 最无脑LCT题解,Dalao们的各种算法都比这个好多啦... 唯一的好处就是只管码代码就好了 开战cut,停战link,询问findroot判连通性 太无脑,应该不用打注释了.常数大就 ...

随机推荐

  1. Abaqus-GUI开发-RSG

    目录 1. GUI开发简介 2. 目标和消息 2.1消息类型和消息ID 2.2消息映射 3. 控件创建 1. GUI开发简介 Abaqus GUI程序开发时,可以采用两种方式创建GUI图形界面. (1 ...

  2. lc 0227

    目录 ✅ 1189. "气球" 的最大数量 描述 解答 cpp py improved py ✅ 784. 字母大小写全排列 描述 解答 c: backTrace !! power ...

  3. 计算机二级-C语言-程序修改题-190123记录-对整数进行取余和除以操作。

    //函数fun功能:将长整型数中每一位上为偶数的数依次取出,构成一个新数放在t中.高位仍在高位,低位仍在低位. //重难点:思路:因为不是字符串,所以可以把问题变成整数的操作,采用取余和除的操作.对整 ...

  4. MongoDB-1 入门

    基础概念 MongoDB 是非关系型数据库,也就是nosql,存储json数据格式会非常灵活,要比mysql更好,同时也能为mysql分摊一部分的流量压力.另外呢,对于非事务的数据完全可以保存到Mon ...

  5. python中os.path.abspath与os.path.realpath 区别

    python中os.path.abspath与os.path.realpath 区别cd /homemkdir amkdir btouch a/1.txtln -s /home/a/1.txt /ho ...

  6. LNMP环境搭建(PHP7.4.0)

    目录 准备工作 安装wget 安装net-tools 安装vim 配置显示行号 关闭防火墙 安装Nginx 安装依赖 编译安装Nginx 配置环境变量 Systemd管理 安装MySQL 安装依赖 下 ...

  7. 商品呢拖拽到购物车,appendChild的剪切功能

    今天来到了妙味课堂的html5课程的第2张的第8节,讲的是把商品拖拽到购物车的演示.其中有一个关于appendChild的使用,,每次拖拽都会触发这个方法,但是每次之后,却还是只有一个总价,好吧,说不 ...

  8. python学习笔记:分支 与 循环

    if 语句 if 条件: ...... # 条件为真的时候,执行缩进的代码 if 条件: ...... # 条件为真的时候执行 else: ...... # 条件为假的时候执行 if 条件1: ... ...

  9. Bugku - CTF加密篇之滴答~滴

    滴答~滴 答案格式KEY{xxxxxxxxx}

  10. vmware虚拟机linux添加硬盘后先分区再格式化操作方法

    先在虚拟机里填加硬盘,如图. 进入linux后台,df-l ,没有显示sdc盘,更切换的是,在fdisk中,却有sdc 看fdisk -l,确实有sdc. 说明sdc还没有分区,也没有格式化,也没有挂 ...