HZOJ Weed
作者的题解:
如果一段操作被执行,会对整个栈有什么影响呢?
把栈弹出若干个数后再插入若干个数。
线段树:
每个点纪录三个值:执行完这段操作后会删多少个,再插多少个,插的和一共是多少。
合并值时再用一个函数查找左孩子被从右删除若干个后剩下的插入总和是多少。
建树复杂度O( N log N ), 单次查询复杂度O( log ^ 2 N), 总复杂度O( N log N + Q log ^2 N ).
树袋熊学长的题解:
• 实际上,每个加数和删除的操作可以看作是入栈和弹栈操作,之后可以用线段树维护多个操作间的关系。线段树的下标是操作时间,由于我们想得到整个序列经过修改操作后的结果,因此线段
树上维护四个信息:
s:区间内加数总和(仅考虑区间内部影响);nd:当前区间向前删除数字的数量;
na:当前区间内“净”加的元素数。
sd:当前区间被右兄弟删除后的总和。 ※仅对左儿子维护此信息。
• 我们通过维护以上四个标记,就可以得到答案(root->s)。现在我们考虑如何维护信息。首先,在建树或修改时,只需要将叶子节点的前三个标记维护好即可;在递归返回时,再计算最后一个。如果左儿子不够右儿子删,那么非常简单,直接利用这几个标记计算即可,l->sd=0。
比较麻烦的是左儿子不被删光的情况。我们先实现一个函数cal(x),利用sd标记计算在当前区间中删去x个元素后的和• 有了这个函数,我们就可以非常方便地计算左儿子的sd,维护其
他标记了,不再赘述。由于这个奇怪的函数在每层节点都会调用,而一共有O(logn)层节点,所以线段树操作的时间复杂度变为O(log 2 n),总时间复杂度也比常规的线段树多一个log。
• 难点主要在于使用额外的函数维护信息,并正确的讨论各种情况。
• 考试时一定要想清楚,时间复杂度是靠“链状”延伸的维护函数保障的,如果不小心写成了两边都下去,就变成O(n 2 )了。
还是说我自己咋写的吧,
用线段树维护操作(好象是第二次碰到这种题),对于线段树的每个节点,维护三个信息,del当前节点删除其左兄弟几个元素,add只考虑当前区间影响区间内的元素个数,val只考虑当前区间影响区间内的和。
建树时对于叶子节点就很容易了,直接赋值就行了。下面考虑怎么合并,分三种情况:
- add(ls(x))==del(rs(x)),相当于x节点的右儿子正好删掉了左儿子的所有元素,于是 del(x)=del(ls(x)),add(x)=add(rs(x)),val(x)=val(rs(x);
- add(ls(x))< del(rs(x)),x节点的右儿子删掉了左儿子的所有元素还要多,于是del(x)=dal(ls(x))+del(rs(x))-add(ls(x)),add(x)=add(rs(x)),val(x)=val(rs(x));
- add(ls(x))> del(rs(x)),x节点的有儿子没有全部删掉左儿子的所有元素,于是 del(x)=del(ls(x));add(x)=add(rs(x))+add(ls(x))-del(rs(x));val(x)=val(rs(x))+cal(ls(x),del(rs(x)));
cal(k,x)表示k节点的区间删掉结尾x个元素后的和:
int cal(int k,int x)
{
if(x==add(rs(k)))return val(k)-val(rs(k));
if(x<add(rs(k))) return val(k)-val(rs(k))+cal(rs(k),x);
if(x>add(rs(k))) return cal(ls(k),x-add(rs(k))+del(rs(k)));
}
到这里大概就没什么了。
最后答案为val(1),对于每次修改直接递归到对应叶子节点即可。
#include<iostream>
#include<cstdio>
#define MAXN 200100
#define LL long long
using namespace std;
struct tree
{
int l,r,del,add,val;
#define l(x) tr[x].l
#define r(x) tr[x].r
#define del(x) tr[x].del
#define add(x) tr[x].add
#define val(x) tr[x].val
#define ls(x) (x<<1)
#define rs(x) (ls(x)+1)
}tr[MAXN*];
int m,q,k[MAXN],v[MAXN];
int cal(int k,int x)
{
if(x==add(rs(k)))return val(k)-val(rs(k));
if(x<add(rs(k))) return val(k)-val(rs(k))+cal(rs(k),x);
if(x>add(rs(k))) return cal(ls(k),x-add(rs(k))+del(rs(k)));
}
void updata(int x)
{
if(add(ls(x))==del(rs(x)))
{
del(x)=del(ls(x));add(x)=add(rs(x));val(x)=val(rs(x));
}
if(add(ls(x))<del(rs(x)))
{
del(x)=del(ls(x))+del(rs(x))-add(ls(x));
add(x)=add(rs(x));
val(x)=val(rs(x));
}
if(add(ls(x))>del(rs(x)))
{
del(x)=del(ls(x));
add(x)=add(rs(x))+add(ls(x))-del(rs(x));
val(x)=val(rs(x))+cal(ls(x),del(rs(x)));
}
}
void build(int x,int l,int r)
{
l(x)=l,r(x)=r;
if(l==r)
{
if(k[l]==) del(x)=,val(x)=v[l],add(x)=;
else del(x)=v[l],val(x)=,add(x)=;
return;
}
int mid=(l+r)>>;
build(ls(x),l,mid);
build(rs(x),mid+,r);
updata(x);
}
void change(int x,int t,int k,int v)
{
if(l(x)==r(x))
{
if(k==)del(x)=,val(x)=v,add(x)=;
else del(x)=v,val(x)=,add(x)=;
return;
}
int mid=(l(x)+r(x))>>;
if(t<=mid)change(ls(x),t,k,v);
else change(rs(x),t,k,v);
updata(x);
}
signed main()
{
/// freopen("weed.in","r",stdin); cin>>m>>q;
for(int i=;i<=m;i++)
cin>>k[i]>>v[i];
build(,,m);
int c,kk,vv;
for(int i=;i<=q;i++)
{
cin>>c>>kk>>vv;
change(,c,kk,vv);
cout<<val()<<endl;
}
}
HZOJ Weed的更多相关文章
- 【Foreign】Weed [线段树]
Weed Time Limit: 20 Sec Memory Limit: 512 MB Description 从前有个栈,一开始是空的. 你写下了 m 个操作,每个操作形如 k v : 若 k ...
- 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护
线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治.他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还 ...
- 8.10 NOIP模拟测试16 Blue+Weed+Drink
T1 Blue 贪心,每次跳得时候跳能跳到的最远的地方,跳过的就把他设为0,每次二分找到位置,一直跳就行,如果能跳到的位置就是当前位置或比当前位置还小(数组里现在呆着的这一块石头,二分得到的就是当前位 ...
- 联赛模拟测试20 C. Weed
题目描述 \(duyege\) 的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹. 为了查出真相,\(duyege\) 准备修好电脑之后再进行一次金坷垃的模拟实验. 电脑上面有若干层金坷垃,每次只能在 ...
- NOIP模拟测试16「Drink·blue·weed」
话说这次考试 Drink 非常棒的一道卡常练习题,适合练习卡常 真的很棒 前置卡常知识 1.char要比int快 char是最快的 输出putchar,输入getchar 在这个题快了7000豪 2. ...
- ABC 203 F - Weed (DP)
ABC203F - Weed 题意转述 S t e v e \rm Steve Steve 和 A l e x \rm Alex Alex 正在下界( N e t h e r l e n d \rm ...
- hzoj 2301(莫比乌斯反演)
题意 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公 数. 思路: 与先前的那个相比,这次a,c并不一定 ...
- HZOJ 单
两个子任务真的是坑……考试的时候想到了60分的算法,然而只拿到了20分(各种沙雕错,没救了……). 算法1: 对于测试点1,直接n遍dfs即可求出答案,复杂度O(n^2),然而还是有好多同学跑LCA/ ...
- Weed:线段树
观察复杂度,是log级别以下回答询问的. O(1)?逗我kx呢? 自然而然地想到线段树. 学长讲的原题啊考场上还不会打. 线段树上的每个节点都表示一个操作区间. 线段树上维护的权值有3个:这个子区间一 ...
随机推荐
- TZ_08_maven私服项目的上传和下载
1. 需求 正式开发,不同的项目组开发不同的工程. ssm_dao工程开发完毕,发布到私服. 2下载 nexus Nexus 是 Maven 仓库管理器,通过 nexus 可以搭建 maven 仓 ...
- iphone越狱开发之Class-Dump
刚刚开始接触ios越狱开发,现在开始纪录每天的点滴进展 装载请注明 http://www.cnblogs.com/xiongwj0910/archive/2012/08/16/2642988.html ...
- 2018-2-13-wpf-如何使用-Magick.NET-播放-gif-图片
title author date CreateTime categories wpf 如何使用 Magick.NET 播放 gif 图片 lindexi 2018-2-13 17:23:3 +080 ...
- I Love Palindrome String
I Love Palindrome String 时间限制: 2 Sec 内存限制: 128 MB 题目描述 You are given a string S=s1s2..s|S| containi ...
- python中星号
第一种情况:用在两表达式的中间,*表示乘法,**表示取幂,如: 1 2 3 4 >>> 2*5 10 >>> 2**7 128 第二种情况:用在变量的前面. 1,向 ...
- POJ 1150 The Last Non-zero Digit 数论+容斥
POJ 1150 The Last Non-zero Digit 数论+容斥 题目地址: id=1150" rel="nofollow" style="colo ...
- Spring MVC JSON自己定义类型转换
版权声明:版权归博主全部.转载请带上本文链接.联系方式:abel533@gmail.com https://blog.csdn.net/isea533/article/details/28625071 ...
- day38 18-Spring的XML和注解的结合使用
什么情况下使用XML,什么情况下使用注解?又有XML,又有注解,开发的时候使用哪种? XML:结构清晰,配置麻烦. 注解:简单, 它俩的结合点在属性注入上. 两种方式结合:一般使用XML注册Bean, ...
- Gradle基本操作入手
Gradle本身的领域对象主要由Project和Task.Project为Task提供了执行上下文,所有的Plugin要么向Project中添加用于配置Property,要么向Project中添加不同 ...
- PHP开发api接口安全验证的实例,值得一看
php的api接口 在实际工作中,使用PHP写api接口是经常做的,PHP写好接口后,前台就可以通过链接获取接口提供的数据,而返回的数据一般分为两种情况,xml和json,在这个过程中,服务器并不知道 ...