BZOJ_3159_决战
分析:
我使用树剖+splay维护这个东西。
对每条重链维护一棵splay,链加和查询正常做,剩下的链反转如下。
由于一定是深度递增的一条链,我们树剖将它分成从左到右log个区间,提取出对应子树,插入到一个新的splay中。
然后打标记进行反转,将子树归还给log个区间。
时间复杂度\(O(nlogn^2)\)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 200050
typedef long long ll;
#define ls ch[p][0]
#define rs ch[p][1]
#define db(x) cerr<<#x<<" = "<<x<<endl
#define Db(x) cerr<<#x<<endl
#define get(x) (ch[f[x]][1]==x)
int ch[N][2],f[N],sz1[N],rev[N];
int head[N],to[N<<1],nxt[N<<1],fa[N],son[N],top[N],sz2[N],dep[N],cnt,root;
int idx[N],pid[N],id[N],n,m,TOT,tot;
ll sum[N],tag[N],mn[N],mx[N],num[N];
struct Splay {
int rt,bg,ed;
int newnode() {
int p=++tot; return p;
}
void init() {
rt=newnode(); int p=newnode();
ch[rt][1]=p; f[p]=rt; pushup(p); pushup(rt);
}
void pushup(int p) {
sum[p]=sum[ls]+sum[rs]+num[p];
mn[p]=min(mn[ls],min(mn[rs],num[p]));
mx[p]=max(mx[ls],max(mx[rs],num[p]));
sz1[p]=sz1[ls]+sz1[rs]+1;
}
void giv1(int p) {
rev[p]^=1; swap(ls,rs);
}
void giv2(int p,ll d) {
tag[p]+=d; sum[p]+=sz1[p]*d; mn[p]+=d; mx[p]+=d; num[p]+=d;
}
void pushdown(int p) {
if(rev[p]) {
if(ls) giv1(ls);
if(rs) giv1(rs);
rev[p]=0;
}
if(tag[p]) {
if(ls) giv2(ls,tag[p]);
if(rs) giv2(rs,tag[p]);
tag[p]=0;
}
}
void UPD(int x) {
if(x!=rt) UPD(f[x]);
pushdown(x);
}
void rotate(int x) {
int y=f[x],z=f[y],k=get(x);
ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
ch[x][!k]=y; f[y]=x; f[x]=z;
if(z) ch[z][ch[z][1]==y]=x;
if(y==rt) rt=x;
pushup(y); pushup(x);
}
void splay(int x,int y) {
UPD(x);
for(int d;(d=f[x])!=y;rotate(x)) if(f[d]!=y) rotate(get(x)==get(d)?d:x);
}
int find(int x) {
int p=rt;
while(1) {
pushdown(p);
if(sz1[ls]>=x) p=ls;
else {
x-=sz1[ls]+1;
if(!x) return p;
p=rs;
}
}
}
int BUILD(int l,int r,int fa) {
int mid=(l+r)>>1;
int p=newnode();
f[p]=fa;
if(l<mid) ls=BUILD(l,mid-1,p);
if(r>mid) rs=BUILD(mid+1,r,p);
pushup(p);
return p;
}
void build(int x) {
rt=BUILD(1,x+2,0);
}
void update(int x,int y,int z) {
x=x-bg+1,y=y-bg+1;
x=find(x),y=find(y+2);
splay(x,0); splay(y,x);
giv2(ch[y][0],z);
pushup(y); pushup(x);
}
ll qsum(int x,int y) {
x=x-bg+1,y=y-bg+1;
x=find(x),y=find(y+2);
splay(x,0); splay(y,x);
//db(x),db(y);
return sum[ch[y][0]];
}
ll qmin(int x,int y) {
x=x-bg+1,y=y-bg+1;
x=find(x),y=find(y+2);
splay(x,0); splay(y,x);
return mn[ch[y][0]];
}
ll qmax(int x,int y) {
x=x-bg+1,y=y-bg+1;
x=find(x),y=find(y+2);
splay(x,0); splay(y,x);
return mx[ch[y][0]];
}
int split(int x,int y) {
x=x-bg+1,y=y-bg+1;
x=find(x),y=find(y+2);
splay(x,0); splay(y,x);
int p=ch[y][0];
f[p]=0,ch[y][0]=0;
pushup(y); pushup(x);
return p;
}
void insert(int x,int p) {
int y,t=x;
x=find(t+1),y=find(t+2);
splay(x,0); splay(y,x);
ch[y][0]=p; f[p]=y;
pushup(y); pushup(x);
}
void findbug(int p) {
pushdown(p);
if(ls) findbug(ls);
//printf("p=%d num[p]=%lld sz1[p]=%d sum=%lld\n",p,num[p],sz1[p],sum[p]);
if(rs) findbug(rs);
}
}G[N],TMP;
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void df1(int x,int y) {
int i; sz2[x]=1; fa[x]=y;
dep[x]=dep[y]+1;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
df1(to[i],x); sz2[x]+=sz2[to[i]];
if(sz2[to[i]]>sz2[son[x]]) son[x]=to[i];
}
}
void df2(int x,int t) {
int i;
top[x]=t;
idx[x]=++idx[0]; pid[idx[0]]=x;
if(son[x]) df2(son[x],t);
for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) df2(to[i],to[i]);
}
char opt[12];
void INCREASE(int x,int y,int z) {
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
G[id[idx[y]]].update(idx[top[y]],idx[y],z);
y=fa[top[y]];
}
if(dep[x]<dep[y]) swap(x,y);
G[id[idx[y]]].update(idx[y],idx[x],z);
}
ll SUM(int x,int y) {
ll re=0;
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
re+=G[id[idx[y]]].qsum(idx[top[y]],idx[y]);
y=fa[top[y]];
}
if(dep[x]<dep[y]) swap(x,y);
re+=G[id[idx[y]]].qsum(idx[y],idx[x]);
return re;
}
ll MIN(int x,int y) {
ll re=1ll<<60;
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
re=min(re,G[id[idx[y]]].qmin(idx[top[y]],idx[y]));
y=fa[top[y]];
}
if(dep[x]<dep[y]) swap(x,y);
re=min(re,G[id[idx[y]]].qmin(idx[y],idx[x]));
return re;
}
ll MAX(int x,int y) {
ll re=0;
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
re=max(re,G[id[idx[y]]].qmax(idx[top[y]],idx[y]));
y=fa[top[y]];
}
if(dep[x]<dep[y]) swap(x,y);
re=max(re,G[id[idx[y]]].qmax(idx[y],idx[x]));
return re;
}
int lca(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]>dep[top[y]]) swap(x,y);
y=fa[top[y]];
}
return dep[x]<dep[y]?x:y;
}
struct A {
int l,r,id,p;
}a[N];
void clr(int p) {
num[p]=tag[p]=rev[p]=mn[p]=mx[p]=sum[p]=ls=rs=f[p]=sz1[p]=0;
}
void INVERSE(int x,int y) {
if(dep[x]>dep[y]) swap(x,y);
int la=0;
while(top[x]!=top[y]) {
a[++la]=(A){idx[top[y]],idx[y],id[idx[y]],G[id[idx[y]]].split(idx[top[y]],idx[y])};
y=fa[top[y]];
}
a[++la]=(A){idx[x],idx[y],id[idx[x]],G[id[idx[x]]].split(idx[x],idx[y])};
int i;
for(i=la;i;i--) {
TMP.insert(sz1[TMP.rt]-2,a[i].p);
}
TMP.splay(1,0); TMP.splay(2,1);
TMP.giv1(ch[2][0]); TMP.pushup(2); TMP.pushup(1);
for(i=la;i;i--) {
int p=TMP.split(1,a[i].r-a[i].l+1);
G[a[i].id].insert(a[i].l-G[a[i].id].bg,p);
}
clr(1),clr(2); ch[1][1]=2; f[2]=1; sz1[1]=2; sz1[2]=1; TMP.rt=1;
}
int main() {
mn[0]=1ll<<60;
scanf("%d%d%d",&n,&m,&root);
int i,x,y,j=0;
for(i=1;i<n;i++) {
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
df1(root,0),df2(root,root);
for(i=1;i<=n;i++) {
if(top[pid[i]]!=top[pid[i-1]]) j++,G[j].bg=i;
id[i]=j; G[j].ed=i;
}
TMP.init(); TMP.bg=1;
TOT=j;
for(i=1;i<=TOT;i++) {
G[i].build(G[i].ed-G[i].bg+1);
}
int z;
for(i=1;i<=m;i++) {
scanf("%s",opt);
if(opt[0]=='I') {
if(opt[2]=='c') {
scanf("%d%d%d",&x,&y,&z);
INCREASE(x,y,z);
}else {
scanf("%d%d",&x,&y);
INVERSE(x,y);
}
}else if(opt[0]=='S') {
scanf("%d%d",&x,&y);
printf("%lld\n",SUM(x,y));
}else {
if(opt[1]=='a') {
scanf("%d%d",&x,&y);
printf("%lld\n",MAX(x,y));
}else {
scanf("%d%d",&x,&y);
printf("%lld\n",MIN(x,y));
}
}
}
}
/*
5 8 1
1 2
2 3
3 4
4 5
Sum 2 4
Increase 3 5 3
Minor 1 4
Sum 4 5
Invert 1 3
Major 1 2
Increase 1 5 2
Sum 1 5
*/
BZOJ_3159_决战的更多相关文章
- 决战JS(二)
紧接着上次的<决战JS>,分析总结一些比较实用的DEMO与新手分享,望大神拍砖. demo5.点击隐藏: 要实现这个功能只需要知道在onclick事件中加入对父节点的样式dislay设置为 ...
- 决战JS
经过这几日的学习,测试和摸索,算是了解了一些关于javascript 的相关知识吧.学习过程中做出了一些小DEMO,现总结一下实现这些DEMO的基本思路,如有不妥或更为简便的方法,还希望大神拍砖,共同 ...
- 决战大数据之三-Apache ZooKeeper Standalone及复制模式安装及测试
决战大数据之三-Apache ZooKeeper Standalone及复制模式安装及测试 [TOC] Apache ZooKeeper 单机模式安装 创建hadoop用户&赋予sudo权限, ...
- 决战大数据之二:CentOS 7 最新JDK 8安装
决战大数据之二:CentOS 7 最新JDK 8安装 [TOC] 修改hostname # hostnamectl set-hostname node1 --static # reboot now 重 ...
- 《决战大数据:驾驭未来商业的利器》【PDF】下载
内容简介 大数据时代的来临,给当今的商业带来了极大的冲击,多数电商人无不"谈大数据色变",并呈现出一种观望.迷茫.手足无措的状态.车品觉,作为一名经验丰富的电商人,在敬畏大数据的同 ...
- Docker决战到底(三) Rancher2.x的安装与使用 - 简书
原文:Docker决战到底(三) Rancher2.x的安装与使用 - 简书 image.png 当越来越多的容器化应用被部署,一个可以管理编排这些容器的工具此时就显得尤为重要了.目前容器编排领域 ...
- Serverless 与容器决战在即?有了弹性伸缩就不一样了
作者 | 阿里云容器技术专家 莫源 本文整理自莫源于 8 月 31 日 K8s & cloudnative meetup 深圳场的演讲内容.****关注"阿里巴巴云原生" ...
- BZOJ 3159: 决战 解题报告
BZOJ 3159: 决战 1 sec 512MB 题意: 给你一颗\(n\)个点,初始点权为\(0\)的有跟树,要求支持 Increase x y w 将路径\(x\)到\(y\)所有点点权加上\( ...
- BZOJ3159: 决战
方法很简单,树剖,把区间提取出来,打翻转标记,再放回去. 注意:由于某种原因,我写的是把题目中的r忽略掉的一般情况,否则简单得多. 本来以为写起来也很简单T_T #include<bits/st ...
随机推荐
- 15:取近似值ApproximateValue
题目描述 写出一个程序,接受一个正浮点数值,输出该数值的近似整数值.如果小数点后数值大于等于5,向上取整:小于5,则向下取整. 输入描述:输入一个正浮点数值 输出描述:输出该数值的近似整数值 输入例子 ...
- vue proxyTable
Vue-cli proxyTable 解决开发环境的跨域问题 字数474 阅读1685 评论1 喜欢3 和后端联调时总是会面对恼人的跨域问题,最近基于Vue开发项目时也遇到了这个问题,两边各自想了一堆 ...
- 企业级API设计
最近对service的API设计,在team内有些讨论,主要集中在API是足够抽象.通用好呢, 还是具体.易用好? 其实这个是要折衷的,通用的好处是以后更改API的可能性小,但坏处是想要通用,里面的字 ...
- 提高网站打开速度的7大秘籍---依据Yslow工具的优化【转】
很多站长使用虚拟主机来做网站,网页内容一旦很多,网站打开速度就会特别慢,如果说服务器.带宽.CDN这类硬指标我们没有经济实力去做,不妨通过网页代码优化的方式来提高速度,卢松松总结了一些可行性的方法. ...
- 软件工程第3次作业——Visual Studio 2017下针对代码覆盖率的C/C++单元测试
本项目Github地址(同时包括两个作业项目): Assignment03 -- https://github.com/Oberon-Zheng/SoftwareEngineeringAssignme ...
- 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符。 给定一个字符串(不一定全为字母)A及它的长度n。请返回第一个重复出现的字符。保证字符串中有重复字符,字符串的长度小于等于500。
// 第一种方法 // ConsoleApplication10.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include < ...
- 线程池 API (转)
文档原始地址 目录 线程池概述 线程池对象 回调环境对象 工作对象 等待对象 计时器对象 I/O 完成对象 使用清理组简化清理 回调实例 API 随着 Windows Vista® 的发布 ...
- leetCode 90.Subsets II(子集II) 解题思路和方法
Given a collection of integers that might contain duplicates, nums, return all possible subsets. Not ...
- Linux 命令汇总总结相关
玩了linux快一年,简单总结下网络相关的命令,具体每个命令的参数可以用到再细看. 1.ifconfig:查询.设置网卡和IP网段等相关参数,包括MTU.2.ifup.ifdown:这两个命令就是一个 ...
- EasyPlayer-RTSP播放器:从底层到上层专注于RTSP播放Windows、Android、iOS RTSP Player
EasyPlayer-RTSP播放器是一套RTSP专用的播放器,包括有:Windows(支持IE插件,npapi插件).Android.iOS三个平台,是由EasyDSS团队开发和维护的区别于市面上大 ...