BZOJ 3159: 决战

1 sec 512MB

题意:

给你一颗\(n\)个点,初始点权为\(0\)的有跟树,要求支持

  • Increase x y w 将路径\(x\)到\(y\)所有点点权加上\(w\)
  • Sum x y 询问路径\(x\)到\(y\)的点权和
  • Major x y 询问从路径\(x\)到\(y\)最大点权
  • Minor x y 询问最小点权
  • Invert x y 将路径上的点权翻转

有个性质,修改操作一定满足\(x\)为\(y\)祖先或者\(y\)为\(x\)祖先(实际没什么用处)

\(n\le 50000,|w|\le 1000\)

输入格式

第一行有三个整数\(N\)、\(M\)和\(R\),分别表示树的节点数、指令和询问总数,以及树的跟。

接下来\(N-1\)行,每行两个整数\(u\)和\(v\),表示一条边。

接下来\(M\)行,每行描述一个指令或询问,格式见题意描述。

输出格式

对于每个询问操作,输出所求的值。


老年菜鸡选手实在写不动大数据结构题...

有两个做法,暂时只写了一种,有可能一会儿会把另一种补充一下。

考虑树链剖分,但是不能维护翻转

考虑平衡树可以维护翻转

于是我们可以拿平衡树维护树剖的每条链

然后每次修改只有\(\log\)条链,我们把每条链要修改的地方拎出来,然后塞到一个平衡树里面,打一个翻转tag,再塞回去就可以了

用fhqtreap实现起来比较方便

说起来蛮简单,写起来还是蛮难受的的


Code:

#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define ll long long
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
int f=0;x=0;char c=gc();
while(!isdigit(c)) f|=c=='-',c=gc();
while(isdigit(c)) x=x*10+c-'0',c=gc();
if(f) x=-x;
}
void reads(char *s)
{
int k=0;char c=gc();
while(c<'A'||c>'Z') c=gc();
while((c>='a'&&c<='z')||(c>='A'&&c<='Z')) s[k++]=c,c=gc();
}
const int N=5e4+10;
inline void ckmax(int &x,int y){x=x>y?x:y;}
inline void ckmin(int &x,int y){x=x<y?x:y;}
int n,m,r,root[N];
namespace treap
{
int ch[N][2],mx[N],mi[N],siz[N],val[N],dat[N],tag[N],reve[N],tot;
ll sum[N];
#define ls ch[now][0]
#define rs ch[now][1]
void updata(int now)
{
sum[now]=sum[ls]+dat[now]+sum[rs];
siz[now]=siz[ls]+1+siz[rs];
mx[now]=mi[now]=dat[now];
if(ls)
{
ckmax(mx[now],mx[ls]);
ckmin(mi[now],mi[ls]);
}
if(rs)
{
ckmax(mx[now],mx[rs]);
ckmin(mi[now],mi[rs]);
}
}
void Reverse(int now)
{
std::swap(ls,rs),reve[now]^=1;
}
void upt(int now,int d)
{
dat[now]+=d;
tag[now]+=d;
mi[now]+=d;
mx[now]+=d;
sum[now]+=d*siz[now];
}
void pushdown(int now)
{
if(reve[now])
{
if(ls) Reverse(ls);
if(rs) Reverse(rs);
reve[now]=0;
}
if(tag[now])
{
if(ls) upt(ls,tag[now]);
if(rs) upt(rs,tag[now]);
tag[now]=0;
}
}
void split(int now,int &x,int &y,int k)
{
if(!now){x=y=0;return;}
pushdown(now);
if(k<=siz[ls])
y=now,split(ls,x,ch[y][0],k);
else
x=now,split(rs,ch[x][1],y,k-siz[ls]-1);
updata(now);
}
int Merge(int x,int y)
{
if(!x||!y) return x^y;
pushdown(x),pushdown(y);
if(val[x]<val[y])
{
ch[x][1]=Merge(ch[x][1],y);
updata(x);
return x;
}
else
{
ch[y][0]=Merge(x,ch[y][0]);
updata(y);
return y;
}
}
int New(int d)
{
val[++tot]=rand(),siz[tot]=1,sum[tot]=mi[tot]=mx[tot]=dat[tot]=d;
return tot;
}
void ins(int id,int d)
{
root[id]=Merge(root[id],New(d));
}
ll querysum(int id,int l,int r)
{
int x,y,z;
split(root[id],x,y,r);
split(x,x,z,l-1);
ll ret=sum[z];
root[id]=Merge(x,Merge(z,y));
return ret;
}
int querymi(int id,int l,int r)
{
int x,y,z;
split(root[id],x,y,r);
split(x,x,z,l-1);
int ret=mi[z];
root[id]=Merge(x,Merge(z,y));
return ret;
}
int querymx(int id,int l,int r)
{
int x,y,z;
split(root[id],x,y,r);
split(x,x,z,l-1);
int ret=mx[z];
root[id]=Merge(x,Merge(z,y));
return ret;
}
void modify(int id,int l,int r,int w)
{
int x,y,z;
split(root[id],x,y,r);
split(x,x,z,l-1);
upt(z,w);
root[id]=Merge(x,Merge(z,y));
}
}
using treap::modify;
using treap::querysum;
using treap::querymi;
using treap::querymx;
using treap::ins;
using treap::Merge;
using treap::split;
using treap::Reverse;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int top[N],ws[N],siz[N],par[N],dep[N],rk[N],num[N];
void dfs(int now)
{
siz[now]=1;
dep[now]=dep[par[now]]+1;
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=par[now])
{
par[v]=now;
dfs(v);
siz[now]+=siz[v];
if(siz[ws[now]]<siz[v]) ws[now]=v;
}
}
int lin,tot[N];
void dfs(int now,int id,int anc)
{
top[now]=anc;
num[now]=id;
rk[now]=++tot[id];
ins(id,0);
if(ws[now]) dfs(ws[now],id,anc);
for(int v,i=head[now];i;i=Next[i])
if(!num[v=to[i]])
dfs(v,++lin,v);
}
void modi(int x,int y,int w)
{
if(dep[x]<dep[y]) std::swap(x,y);
while(top[x]!=top[y])
{
modify(num[x],1,rk[x],w);
x=par[top[x]];
}
if(dep[x]<dep[y]) std::swap(x,y);
modify(num[x],rk[y],rk[x],w);
}
void qrysum(int x,int y)
{
ll ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
ret+=querysum(num[x],1,rk[x]);
x=par[top[x]];
}
else
{
ret+=querysum(num[y],1,rk[y]);
y=par[top[y]];
}
}
if(dep[x]<dep[y]) std::swap(x,y);
ret+=querysum(num[x],rk[y],rk[x]);
printf("%lld\n",ret);
}
void qrymx(int x,int y)
{
int ret=-(1<<30);
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
ckmax(ret,querymx(num[x],1,rk[x]));
x=par[top[x]];
}
else
{
ckmax(ret,querymx(num[y],1,rk[y]));
y=par[top[y]];
}
}
if(dep[x]<dep[y]) std::swap(x,y);
ckmax(ret,querymx(num[x],rk[y],rk[x]));
printf("%d\n",ret);
}
void qrymi(int x,int y)
{
int ret=1<<30;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
ckmin(ret,querymi(num[x],1,rk[x]));
x=par[top[x]];
}
else
{
ckmin(ret,querymi(num[y],1,rk[y]));
y=par[top[y]];
}
}
if(dep[x]<dep[y]) std::swap(x,y);
ckmin(ret,querymi(num[x],rk[y],rk[x]));
printf("%d\n",ret);
}
void rev(int x,int y)
{
int tx=x,ty=y;
if(dep[x]<dep[y]) std::swap(x,y);
int rt=0;
while(top[x]!=top[y])
{
int id=num[x],k=rk[x],pre;
split(root[id],pre,root[id],k);
rt=Merge(pre,rt);
x=par[top[x]];
}
if(dep[x]<dep[y]) std::swap(x,y);
int id=num[x],l=rk[y],r=rk[x],a,b,c;
split(root[id],a,c,r);
split(a,a,b,l-1);
rt=Merge(b,rt);
Reverse(rt);
x=tx,y=ty;
if(dep[x]<dep[y]) std::swap(x,y);
while(top[x]!=top[y])
{
int id=num[x],k=rk[x],pre;
split(rt,rt,pre,treap::siz[rt]-k);
root[id]=Merge(pre,root[id]);
x=par[top[x]];
}
id=num[x];
root[id]=Merge(a,Merge(rt,c));
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
read(n),read(m),read(r);
for(int u,v,i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);
dfs(r);
dfs(r,++lin,r);
char op[23];
for(int x,y,w,i=1;i<=m;i++)
{
reads(op),read(x),read(y);
if(op[0]=='I')
{
if(op[2]=='c') read(w),modi(x,y,w);
else rev(x,y);
}
else if(op[0]=='S') qrysum(x,y);
else
{
if(op[1]=='a') qrymx(x,y);
else qrymi(x,y);
}
}
return 0;
}

2019.5.22

BZOJ 3159: 决战 解题报告的更多相关文章

  1. BZOJ 3159决战

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3159 题意:给出一棵树,(1)路径加一个值:(2)路径上的节点的值反转(只是值反转,不是节 ...

  2. POJ 3159 Candies 解题报告(差分约束 Dijkstra+优先队列 SPFA+栈)

    原题地址:http://poj.org/problem?id=3159 题意大概是班长发糖果,班里面有不良风气,A希望B的糖果不比自己多C个.班长要满足小朋友的需求,而且要让自己的糖果比snoopy的 ...

  3. BZOJ 2959: 长跑 解题报告

    2959: 长跑 Description 某校开展了同学们喜闻乐见的阳光长跑活动.为了能"为祖国健康工作五十年",同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑 ...

  4. BZOJ 4238 电压 解题报告

    BZOJ 4238 电压 考虑一条边成为答案以后,删去Ta后剩下的图是一个或很多个二分图,即没有奇环 则一条边可以成为答案,当且仅当自己在所有奇环的交上且不在偶环上. 考虑建出dfs树,那么返祖边一定 ...

  5. BZOJ 3328: PYXFIB 解题报告

    BZOJ 3328: PYXFIB 题意 给定\(n,p,k(1\le n\le 10^{18},1\le k\le 20000,1\le p\le 10^9,p \ is \ prime,k|(p- ...

  6. BZOJ 4302 Buildings 解题报告

    这个题好像很有趣的样子. 题目分析: 房间都是 $1\times k$ 的,也就是一条一条的.这个好像比较显然的样子. 一个房间如果要覆盖某个格子$u$,那么这个房间的面积至少为 $dis(u, Bo ...

  7. BZOJ 3160 万径人踪灭 解题报告

    这个题感觉很神呀.将 FFT 和 Manacher 有机结合在了一起. 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ ...

  8. BZOJ 4127 Abs 解题报告

    这个题感觉很厉害的样子.. 首先我们注意到一点:每次加的 $d$ 都是非负的. 那么就说明一个数只可能从负数变成非负数并且只会变一次. 所以我们就可以暴力地去改变一个数的正负情况. 然后我们就可以用树 ...

  9. BZOJ 3953 Self-Assembly 解题报告

    首先,我们可以先考虑一个暴力一点的算法: 对于任意两个分子,如果它们能以至少一种进行匹配,那么我们就在这两个分子之间连一条边. 然后如果我们能找到一个环,就说明是 unbounded,否则就是 bou ...

随机推荐

  1. 【leetcode】907. Sum of Subarray Minimums

    题目如下: 解题思路:我的想法对于数组中任意一个元素,找出其左右两边最近的小于自己的元素.例如[1,3,2,4,5,1],元素2左边比自己小的元素是1,那么大于自己的区间就是[3],右边的区间就是[4 ...

  2. for循环语句示例

    for循环语句示例 一判断/var/目录下所有文件的类型 完整脚本 [root@centos73 ~]# cat shell_scripts/filetype.sh #!/bin/bash #Auth ...

  3. OC学习篇之---谓词(NSPredicate)

    在前一篇文章中我们介绍了OC中一个重要技术通知:http://blog.csdn.net/jiangwei0910410003/article/details/41923401,今天我们在来看一下OC ...

  4. git代码提交步骤

    常用的步骤: 1)假如本地想关联git仓库,那么先git  init,git remote add origin [git地址] 2)假如是想直接从git仓库拉下来,那么git clone [git地 ...

  5. Excel表格 函数

    1.四则运算(加.减.乘.除).求和.平均.计数.最值. 2. 逻辑函数 (IF函数.NOT函数.等) 3.时间和日期 ( NOW 返回当前日期和时间.等) 4.数学与三角函数 5.文本 ( LOWE ...

  6. Memory Analyzer Tool定位Java heap space内存泄漏

    java heap space是一个很蛋疼的问题,如果开发调试时遇到还好,如果是在项目上线后运行一段时间后,才抛出该异常,那真的很悲剧(那你得找代码中到底是哪里内存泄露了),这真是一个悲伤的故事. 1 ...

  7. HTML5: HTML(5) 代码规范

    ylbtech-HTML5: HTML(5) 代码规范 1.返回顶部 1. HTML(5) 代码规范 HTML 代码约定 很多 Web 开发人员对 HTML 的代码规范知之甚少. 在2000年至201 ...

  8. MyEclipse增强代码补全

    MyElipse的默认代码提示功能隐藏了许多细节,需要开发者手动设置,一起来设置吧,让你的myeclpse更强大. 方法 1 打开MyEclipse 6.0.1,然后“window”→“Prefere ...

  9. 25. 服务器性能监控之nmon工具介绍

    nmon介绍: nmon是一个简单的性能监测工具,可以监测CPU.内存.网络等的使用情况. 步骤: 1.下载nmon(根据你的操作系统下载),地址 2.nmon文件部署到服务器中 3.启动nmon(注 ...

  10. Rust <6>:闭包

    单线程环境: 从宿主环境中捕获的变量,是引用,会改变原有的值,与 golang 的闭包行为一样: 以参数形式传入的变量,默认会发生 move:而 golang 的闭包参数,是宿主环境的副本,相当于在 ...