题解 P3950 【部落冲突】
树链剖分吼啊
一看就看出是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"); //不行就……
}
}
}
另外推荐题目
题解 P3950 【部落冲突】的更多相关文章
- luogu题解 P3950部落冲突--树链剖分
题目链接 https://www.luogu.org/problemnew/show/P3950 分析 大佬都用LCT,我太弱只会树链剖分 一个很裸的维护边权树链剖分题.按照套路,对于一条边\(< ...
- lupgu P3950 部落冲突
题目链接 luogu P3950 部落冲突 题解 树剖线段树可以 lct还行 代码 #include<cstdio> #include<algorithm> inline in ...
- 洛谷 P3950 部落冲突 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例1 输出样例1 输入样例2 输出样例2 输入样例3 输出样例3 说明 思路 AC代码 总结 题面 题目链接 P3 ...
- 洛谷P3950 部落冲突 [LCT]
题目传送门 部落冲突 格式难调,体面就不放了. 分析: julao们应该都看得出来就是个$LCT$板子,战争就$cut$,结束就$link$,询问就$find$.没了... 太久没打$LCT$,然后发 ...
- 【luogu P3950 部落冲突】 题解
题目连接:https://www.luogu.org/problemnew/show/P3950 1.像我这种学数据结构学傻了的 2.边权化点权 所有点权初始化0 3.对于战争 将深度较深的-1,对于 ...
- 【题解】Luogu P3950 部落冲突
原题传送门 这题用Link-Cut-Tree解决,Link-Cut-Tree详解 我们用Link-Cut-Tree维护连通性(十分无脑) 一开始先把树中每条边的两端连接 U操作:把u,v两个点连起来 ...
- [题解] 洛谷P3950 部落冲突
传送门 拿到题目,一看 裸LCT (其实是我懒得打,splay又臭又长) 首先,这道题的意思就是删掉一些边 所以常规操作 点权转边权 之后对于战争操作,在对应的边上+1 对于和平操作,在对应的边上-1 ...
- 【刷题】洛谷 P3950 部落冲突
题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多 ...
- P3950 部落冲突
题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多 ...
- 洛谷P3950 部落冲突(LCT)
洛谷题目传送门 最无脑LCT题解,Dalao们的各种算法都比这个好多啦... 唯一的好处就是只管码代码就好了 开战cut,停战link,询问findroot判连通性 太无脑,应该不用打注释了.常数大就 ...
随机推荐
- Flutter Android 真机器调试 、模拟器调试、Vscode 中开发 Flutter 应用
必备条件: 1.准备一台 Android 手机 2.手机需要开启调试模式 3.用数据线把手机连上电脑 4.手机要允许电脑进行 Usb 调试 5.手机对应的 sdk 版本必须安装 注意: 1.关闭电脑上 ...
- C语言:输入一个数,输出比这个数小的所有素数,并求出个数。
//C语言:输入一个数,输出比这个数小的所有素数,并求出个数. #include<conio.h> #include<stdio.h> #include<stdlib.h ...
- JS-正则表达式常规运用
限制文本框只能输入0和正数 <input type="text" onkeyup="this.value=this.value.replace(/\D/g,'')& ...
- centos 6.5 防火墙通过 80 和 3306 端口
vim /etc/sysconfig/iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPU ...
- 使用python实现归并排序、快速排序、堆排序
归并排序 使用分治法:分而治之 分: 递归地拆分数组,直到它被分成两对单个元素数组为止. 然后,将这些单个元素中的每一个与它的对合并,然后将这些对与它们的对等合并,直到整个列表按照排序顺序合并为止. ...
- Java电子书高清PDF集合免费下载
这份资源是我经过多年积累才整理归类出来,有很多电子书我觉质量还是非常高的,由于电子书太多我也是用业余时间挑着看的,这么多资源自己保存着也是浪费,就想着现在把资源分享出来,希望能真正帮到大家: 资源我都 ...
- OpenCV介绍
OpenCV 是什么 OpenCV是计算机视觉开源库,主要算法涉及图像处理和机器学习相关方法. 是 Intel 公司贡献出来的,俄罗斯工程师贡献大部分 C/C++ 代码 在多数图像处理相关的应用程序中 ...
- Python os模块、os.path模块常用方法
os模块:os模块在python中包含普遍的操作系统功能,下面列出了一些在os模块中比较有用的部分. os.sep 可以取代操作系统特定的路径分隔符.windows下为 "\" o ...
- Cisco Cat4500系列High CPU故障步骤摘要
在实际网络环境中,很多时候都会出现设备high CPU的情况,有些时候可能是bug,而某些情况下,也可能是网络中发生了变化,导致了设备出现high CPU情况,这里主要记录一下Cisco Cat450 ...
- Nexus 3048的NX-OS升级方法
1.System Software和Kick Start 与普通IOS设备不同,NX OS升级时,共有2个文件需要升级.安装,如果只安装其中一个,可能会导致设备重启后无法进入系统.这2个文件包括: N ...