题目链接

分析:

我使用树剖+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_决战的更多相关文章

  1. 决战JS(二)

    紧接着上次的<决战JS>,分析总结一些比较实用的DEMO与新手分享,望大神拍砖. demo5.点击隐藏: 要实现这个功能只需要知道在onclick事件中加入对父节点的样式dislay设置为 ...

  2. 决战JS

    经过这几日的学习,测试和摸索,算是了解了一些关于javascript 的相关知识吧.学习过程中做出了一些小DEMO,现总结一下实现这些DEMO的基本思路,如有不妥或更为简便的方法,还希望大神拍砖,共同 ...

  3. 决战大数据之三-Apache ZooKeeper Standalone及复制模式安装及测试

    决战大数据之三-Apache ZooKeeper Standalone及复制模式安装及测试 [TOC] Apache ZooKeeper 单机模式安装 创建hadoop用户&赋予sudo权限, ...

  4. 决战大数据之二:CentOS 7 最新JDK 8安装

    决战大数据之二:CentOS 7 最新JDK 8安装 [TOC] 修改hostname # hostnamectl set-hostname node1 --static # reboot now 重 ...

  5. 《决战大数据:驾驭未来商业的利器》【PDF】下载

    内容简介 大数据时代的来临,给当今的商业带来了极大的冲击,多数电商人无不"谈大数据色变",并呈现出一种观望.迷茫.手足无措的状态.车品觉,作为一名经验丰富的电商人,在敬畏大数据的同 ...

  6. Docker决战到底(三) Rancher2.x的安装与使用 - 简书

    原文:Docker决战到底(三) Rancher2.x的安装与使用 - 简书   image.png 当越来越多的容器化应用被部署,一个可以管理编排这些容器的工具此时就显得尤为重要了.目前容器编排领域 ...

  7. Serverless 与容器决战在即?有了弹性伸缩就不一样了

    作者 | 阿里云容器技术专家 莫源  本文整理自莫源于 8 月 31 日 K8s & cloudnative meetup 深圳场的演讲内容.****关注"阿里巴巴云原生" ...

  8. BZOJ 3159: 决战 解题报告

    BZOJ 3159: 决战 1 sec 512MB 题意: 给你一颗\(n\)个点,初始点权为\(0\)的有跟树,要求支持 Increase x y w 将路径\(x\)到\(y\)所有点点权加上\( ...

  9. BZOJ3159: 决战

    方法很简单,树剖,把区间提取出来,打翻转标记,再放回去. 注意:由于某种原因,我写的是把题目中的r忽略掉的一般情况,否则简单得多. 本来以为写起来也很简单T_T #include<bits/st ...

随机推荐

  1. sprint3 【每日scrum】 TD助手站立会议第六天

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 在添加日程类型处添加了选择闹钟间隔多长时间相应,并写了闹钟运行的类 在日历各个事件上都增加闹钟显示,并将数据传递给日程和时间表 感觉跟楠哥在设 ...

  2. java面试笔记(2019)

    1. 堆啊,栈啊,内存溢出原因 2. Dubbo原理 3. Reids线程 4. 线程池安全 5. linux查看线程命令 6. ABA

  3. 12306 外包给阿里巴巴、IBM 等大企业做是否可行?

    知乎上看到的,转载过来,雅俗共赏 12306首秀被骂的狗血喷头后铁道部找来IBM.阿里巴巴等大企业要解决方式,给出的条件是资金管够可是问题得解决. 几大企业最后都拒绝了(当中阿里巴巴最后负责了排队系统 ...

  4. 多媒体开发之---h264 高度和宽度获取

    ( School of Computer Science & Technology, Soochow University,SuZhou 215006:) Abstract: H.264 is ...

  5. C#中的let字句应用示例

    一.应用场景 在查询表达式中,存储子表达式的结果有时很有用,这样可以在随后的子句中使用. 可以使用 let 关键字完成这一工作,该关键字可以创建一个新的范围变量,并且用您提供的表达式的结果初始化该变量 ...

  6. PHP进阶知识

    关于PHP程序员技术职业生涯规划:http://rango.swoole.com/ Micro Service Framework For PHP:https://github.com/pinguo/ ...

  7. Android中RelativeLayout各个属性及其含义

    android:layout_above="@id/xxx"  --将控件置于给定ID控件之上android:layout_below="@id/xxx"  - ...

  8. rabbitmq 安装-单点

    centos6.5  rabbitmq搭建 环境:centos6.5 192.168.9.41   安装rabbitmq需要先安装erlang.rabbitmq3.6版本需要erlang R16B03 ...

  9. Windows操作系统远程Linux服务器传输文件方法(以EasyDSS云平台、EasyNVR上传部署为例)

    本文转自博客:https://blog.csdn.net/black_3717/article/details/79769406 问题背景: 之前给客户部署我们一款EasyDSS云平台(配合EasyN ...

  10. java设计模式之迭代器模式

    一.迭代器模式简介 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 迭代器模式让我们能游走于聚合内的每一个元素,而又不暴露内部的表示.把游走的任务放在迭代器上,而不是 ...