Stanford Local 2016 G "Ground Defense"(线段树)
题意:
有 n 个城市,编号 1~n;
有两种操作:Update,Query
Update:
E i s a d
更新区间[ i,i+d-1 ], i 节点降落 s 人, i+1 节点降落 s+a 人, i+2 节点降落 s+2*a 人,......, i+d-1 节点降落 s+(d-1)*a 人;
W i s a d
更新区间[ i-d+1,i ], i 节点降落 s 人, i-1 节点降落 s+a 人, i-2 节点降落 s+2*a 人,......, i-d+1 节点降落 s+(d-1)*a 人;
简言之,从 i 节点下降 s 人开始,向东(右),西(左)下降的人数依次 +a;
Query: i
查询在节点 i 降落的总人数。
题解:
看到这道题,第一反应是线段树区间更新,那具体怎么个更新法呢?
首先看线段树中定义的元素:
struct SegmentTree
{
int l,r;
ll s;//l处增加s人
ll a;//从l到r依次变化a人
int mid()
{
return l+((r-l)>>);
}
}segTree[*maxn];
定义Update()函数,具体如下:
void Update(int l,int r,int pos,ll s,ll a)
{
if(segTree[pos].l == l && segTree[pos].r == r)
{
segTree[pos].s += s;//pos节点中的s增加s
segTree[pos].a += a;//pos节点中的a增加a
return ;
}
pushDown(pos);//向下更新 int mid=segTree[pos].mid();
if(r <= mid)
Update(l,r,ls(pos),s,a);
else if(l > mid)
Update(l,r,rs(pos),s,a);
else
{
ll d=mid+-l;
Update(l,mid,ls(pos),s,a);
Update(mid+,r,rs(pos),s+d*a,a);//注意右儿子更新的s值
}
}
如果更新操作为 E i s a d :
调用函数 Update( i , i+d-1 , 1 , s , a );
反之,如果更新操作为 W i s a d ⇔ E (i-d+1) ( s+(d-1)*a ) (-a) d
调用函数 Update( (i-d+1) , i , 1 , s+(d-1)*a , -a );
更新函数中的pushDown()函数是非常重要的,其决定了此算法的正确与否:
//将pos节点更新的状态传给儿子节点
void pushDown(int pos)
{
ll &s=segTree[pos].s;
ll &a=segTree[pos].a;
if(s)//如果s不为0,说明在这之前曾更新过pos节点
{
//左儿子的更新
segTree[ls(pos)].s += s;
segTree[ls(pos)].a += a; /**
右儿子的更新操作
注意 segTree[rs(pos)].s 增加的值
具体原因留给读者自己思索
*/
segTree[rs(pos)].s += s+a*(segTree[rs(pos)].l-segTree[ls(pos)].l);
segTree[rs(pos)].a += a;
}
s=;
a=;
}
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=5e5+; int n,m;
struct SegmentTree
{
int l,r;
ll s;//l处增加s人
ll a;//从l到r依次增加a
int mid()
{
return l+((r-l)>>);
}
}segTree[*maxn]; void pushDown(int pos)
{
ll &s=segTree[pos].s;
ll &a=segTree[pos].a;
if(s)
{
segTree[ls(pos)].s += s;
segTree[ls(pos)].a += a; /**
右儿子的更新操作
注意 segTree[rs(pos)].s 增加的值
具体原因留给读者自己思索
*/
segTree[rs(pos)].s += s+a*(segTree[rs(pos)].l-segTree[ls(pos)].l);
segTree[rs(pos)].a += a;
}
s=;
a=;
}
void buildSegTree(int l,int r,int pos)
{
segTree[pos].l=l;
segTree[pos].r=r;
segTree[pos].s=;
segTree[pos].a=;
if(l == r)
return ; int mid=l+((r-l)>>);
buildSegTree(l,mid,ls(pos));
buildSegTree(mid+,r,rs(pos));
}
void Update(int l,int r,int pos,ll s,ll a)
{
if(segTree[pos].l == l && segTree[pos].r == r)
{
segTree[pos].s += s;
segTree[pos].a += a;
return ;
}
pushDown(pos);//向下更新 int mid=segTree[pos].mid();
if(r <= mid)
Update(l,r,ls(pos),s,a);
else if(l > mid)
Update(l,r,rs(pos),s,a);
else
{
ll d=mid+-l;
Update(l,mid,ls(pos),s,a);
Update(mid+,r,rs(pos),s+d*a,a);//注意右儿子更新的s值
}
}
ll Query(int x,int pos)
{
if(segTree[pos].l == segTree[pos].r)
return segTree[pos].s;
pushDown(pos); int mid=segTree[pos].mid();
if(x <= mid)
return Query(x,ls(pos));
else
return Query(x,rs(pos));
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
int test;
scanf("%d",&test);
while(test--)
{
scanf("%d%d",&m,&n);
buildSegTree(,n,);
while(m--)
{
char order[];
scanf("%s",order);
if(order[] == 'U')
{
char x[];
int i,s,a,d;
scanf("%s%d%d%d%d",x,&i,&s,&a,&d);
if(x[] == 'E')
{
//r=min()是为了防止数据出错使得 i+d-1 > n
int r=min(n,i+d-);
Update(i,r,,s,a);
}
else
{
//l=max()是为了防止数据出错使得 i-d+1 < 1
int l=max(,i-d+);
Update(l,i,,1ll*s+1ll*a*(d-),-a);
}
}
else
{
int i;
scanf("%d",&i);
printf("%lld\n",Query(i,));
}
}
}
return ;
}
Stanford Local 2016 G "Ground Defense"(线段树)的更多相关文章
- BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流
BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流 Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1 ...
- BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin [线段树优化建边]
4276: [ONTAK2015]Bajtman i Okrągły Robin 题意:\(n \le 5000\)个区间\(l,r\le 5000\),每个区间可以选一个点得到val[i]的价值,每 ...
- Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)
题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...
- 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流
[BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...
- codeforces 626 G. Raffles(线段树+思维+贪心)
题目链接:http://codeforces.com/contest/626/problem/G 题解:这题很明显买彩票肯定要买贡献最大的也就是说买p[i]*(num[i]+1)/(num[i]+a[ ...
- LYOI 2016 Summer 函数 【线段树】
<题目链接> 题目大意: fqk 退役后开始补习文化课啦,于是他打开了数学必修一开始复习函数,他回想起了一次函数都是 f(x)=kx+b的形式,现在他给了你n个一次函数 fi(x)=kix ...
- ACM-ICPC 2018 徐州赛区网络预赛-G Trace(线段树的应用
Problem:Portal传送门 Problem:Portal传送门 原题目描述在最下面. 我理解的题意大概是:有n次涨潮和退潮,每次的范围是个x×y的矩形,求n次涨退潮后,潮水痕迹的长度. ...
- Stanford Local 2016 E "Election of Evil"(搜索(正解)或并查集(划掉))
传送门 题意: 给出集合U,V,集合U有n个元素,集合V有m个元素: 有 m 个操作,mi : s1 s2 有一条s1指向s2的边(s1,s2可能属于第三个集合,暂且称之为K集合): 指向边具有传递性 ...
- 华中农业大学第四届程序设计大赛网络同步赛 G.Array C 线段树或者优先队列
Problem G: Array C Time Limit: 1 Sec Memory Limit: 128 MB Description Giving two integers and and ...
随机推荐
- FT 软件项目管理
FT 软件项目: 以Feature Team形式组织起来的软件研发项目. 项目是临时组织不是长期组织. 人员临时组织起来, 无组织汇报关系.大家需要充分理解和认同项目的目标,通过项目获得技术.经验. ...
- python3操作MySQL数据库,一次插入多条记录的方法
这里提供一个思路,使用字符串拼接的方法,将sql语句拼接出来,然后去执行: l = ["] s = '-' print(s.join(l))
- Navicat Premium 12.0.24安装与激活(亲测已成功激活)
另请参见:Navicat Premium 12.0.18 / 12.0.24安装与激活 另请参见:Navicat Premium 12安装与激活(亲测已成功激活) 说明: 本主亲自验证过,可以激活! ...
- LeetCode算法题-Maximum Depth of N-ary Tree(Java实现)
这是悦乐书的第261次更新,第274篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第128题(顺位题号是559).给定n-ary树,找到它的最大深度.最大深度是从根节点到 ...
- 日志学习系列(四)——NLog实例
具体不想介绍了,新建一个解决方案 ,直接用NuGet安装就行了 具体项目代码可以在https://github.com/qiuxianhu/SimpleNLog下载
- Python爬虫【实战篇】百度翻译
先看代码 import requests headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS ...
- git-将dev代码合并到test
1. 在dev分支上刚开发完项目,执行以下命令: git add git commit -m 'dev' git push -u origin dev 2.切换到test分支上 如果是多人开发,先把远 ...
- C语言作业评价标准
C语言作业评价标准 作业内容: 每周作业分为基础作业.挑战作业和预习作业: 基础作业为本周所学内容的巩固: 挑战作业包括但不仅限于所学知识的综合运用: 预习作业为下周所学内容的任务单,要求必须在课前完 ...
- centos7 安装mysql5.7
[root@izbp1buyhgwtrvlxv3u2gqz soft]# wget http://dev.mysql.com/get/mysql57-community-release-el7-8.n ...
- Vultr CentOS 7 安装 Docker
前言 最近在梳理公司的架构,想用 VPS 先做一些测试,然后就开始踩坑了!我用 Vultr 新买了个 VPS. 安装的 CentOS 版本: [root@dbn-seattle ~]# cat /et ...