线段树操作中的一些预判方法【UOJ 228】【codeforces 438D】
来源:互联网 发布:网络陷阱有哪些 编辑:程序博客网 时间:2024/05/22 14:12
一、UOJ 228
作为一个傻逼题,我……我竟然提交了n次!!!
题意
给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:区间加,区间开方,区间求和。
题解
网上大神们的博客里说,对于一次区间开根:
设最大值为maxn,最小值为minn,如果maxn-minn=sqrt(maxn)-sqrt(minn),就可以看成区间减法。(因为减小的值是一样的)
但是,我以为是在一开始判断一次,没想到是在递归中每一次都做判断,所以华丽地TLE了。
惨啊!感觉要完。
细节见代码。
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#define N 100010#define inf 1e16+7#define lson o << 1#define rson o << 1 | 1typedef long long LL;LL sum[N << 2],add[N << 2],maxn[N << 2],minn[N << 2];int ll,rr;void pushup(int o){ sum[o] = sum[lson] + sum[rson]; maxn[o] = max(maxn[lson],maxn[rson]); minn[o] = min(minn[lson],minn[rson]);}void build(int o,int l,int r){ if(l == r) { scanf("%lld",&sum[o]); maxn[o] = minn[o] = sum[o]; return; } int mid = (l+r)>>1; build(lson,l,mid); build(rson,mid+1,r); pushup(o);}void pushdown(int o,int l,int r){ if(add[o] != 0) { int mid = (l+r)>>1; add[lson] += add[o]; maxn[lson] += add[o];minn[lson] += add[o]; add[rson] += add[o]; maxn[rson] += add[o];minn[rson] += add[o]; sum[lson] += add[o]*(mid-l+1); sum[rson] += add[o]*(r-mid); add[o] = 0; }}void update(int o,int l,int r,LL x){ if(ll <= l && rr >= r) { add[o] += x; sum[o] += (r-l+1)*x; maxn[o] += x; minn[o] += x; return; } pushdown(o,l,r); int mid = (l+r)>>1; if(ll <= mid) update(lson,l,mid,x); if(rr > mid) update(rson,mid+1,r,x); pushup(o);}void solve_add(int o,int l,int r,LL x){ add[o] += x; sum[o] += (r-l+1)*x; maxn[o] += x; minn[o] += x;}void solve(int o,int l,int r){ if(ll <= l && rr >= r)//在这里做特判!!! { LL a = maxn[o],b = minn[o]; if((a-b) <= 1 && ((LL)sqrt(a)-(LL)sqrt(b))==(a-b)) { solve_add(o,l,r,(LL)sqrt(a)-a); return;} } int mid = (l+r)>>1; pushdown(o,l,r); if(ll <= mid) solve(lson,l,mid); if(rr > mid) solve(rson,mid+1,r); pushup(o);}LL query(int o,int l,int r){ if(ll <= l && rr >= r) return sum[o]; int mid = (l+r)>>1; pushdown(o,l,r); LL ans = 0; if(ll <= mid) ans += query(lson,l,mid); if(rr > mid) ans += query(rson,mid+1,r); return ans;}LL ask_max(int o,int l,int r){ if(ll <= l && rr >= r) return maxn[o]; int mid = (l+r)>>1; pushdown(o,l,r); LL ans = -1; if(ll <= mid) ans = max(ans,ask_max(lson,l,mid)); if(rr > mid) ans = max(ans,ask_max(rson,mid+1,r)); return ans;}LL ask_min(int o,int l,int r){ if(ll <= r && rr >= r) return minn[o]; int mid = (l+r)>>1; pushdown(o,l,r); LL ans = inf; if(ll <= mid) ans = min(ans,ask_min(lson,l,mid)); if(rr > mid) ans = min(ans,ask_min(rson,mid+1,r)); return ans;}int main(){ int n,m,opt,x; scanf("%d%d",&n,&m); memset(add,0,sizeof(add)); build(1,1,n); while(m--) { scanf("%d%d%d",&opt,&ll,&rr); if(opt == 1) {scanf("%d",&x); update(1,1,n,x);} if(opt == 2) solve(1,1,n); if(opt == 3) printf("%lld\n",query(1,1,n)); } return 0;}
二、CF Round#250 div1 D
题意
一个序列,三个操作。
1、区间取模 2、单点修改 3、区间求和
题解
跟上题差不多,就是找一个合适的判断条件(对于每种判断条件还可以求复杂度,但是窝不会-_-)
多维护一个区间最大值,对于一个符合条件的区间,若最大值小于mod,就可以不进行操作;
同时,当l==r时,直接就是单点修改。
这样就是一道很普通的线段树了。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define lson o << 1#define rson o << 1 | 1#define N 100010typedef long long LL;int setv[N << 2],maxn[N << 2],mod,ll,rr;LL sum[N << 2];void pushup(int o) { sum[o] = sum[lson] + sum[rson]; maxn[o] = max(maxn[lson],maxn[rson]);}void pushdown(int o,int l,int r){ if(setv[o] != -1) { setv[lson] = setv[rson] = setv[o]; maxn[lson] = maxn[rson] = setv[o]; int mid = (l+r)>>1; sum[lson] =(LL)(mid-l+1) * setv[o]; sum[rson] =(LL)(r-mid) * setv[o]; setv[o] = -1; }}void build(int o,int l,int r){ setv[o] = -1; if(l == r){ scanf("%lld",&sum[o]); maxn[o] = sum[o]; return; } int mid = (l+r)>>1; build(lson,l,mid); build(rson,mid+1,r); pushup(o);}void update(int o,int l,int r){ if(ll <= l && rr >= r) { if(l == r) { sum[o] %= mod; maxn[o] = sum[o]; return;} if(maxn[o] < mod) return; } int mid = (l+r)>>1; pushdown(o,l,r); if(ll <= mid) update(lson,l,mid); if(rr > mid) update(rson,mid+1,r); pushup(o);}void change(int o,int l,int r,int pos,int x){ if(l == r){sum[o] = maxn[o] = x; return;} int mid = (l+r)>>1; pushdown(o,l,r); if(pos <= mid) change(lson,l,mid,pos,x); else change(rson,mid+1,r,pos,x); pushup(o);}LL query(int o,int l,int r){ if(ll <= l && rr >= r) return sum[o]; int mid = (l+r)>>1; LL ans = 0; pushdown(o,l,r); if(ll <= mid) ans += query(lson,l,mid); if(rr > mid) ans += query(rson,mid+1,r); pushup(o); return ans;}int main(){ int n,m,opt; scanf("%d%d",&n,&m); build(1,1,n); while(m--) { scanf("%d%d%d",&opt,&ll,&rr); if(opt == 1) printf("%lld\n",query(1,1,n)); if(opt == 2) {scanf("%d",&mod); update(1,1,n); } if(opt == 3) change(1,1,n,ll,rr); } return 0;}
1 0
- 线段树操作中的一些预判方法【UOJ 228】【codeforces 438D】
- codeforces 438D(线段树)
- Codeforces 438D 线段树 解题报告
- codeforces 339D 简单的线段树操作
- codeforces 19D 线段树
- Codeforces 482B Interesting Array 构造+线段树判可行
- CodeForces 438D 浅谈区间取模线段树
- CodeForces 438D 线段树区间取模
- CodeForces 228D. Zigzag(线段树暴力)
- 【线段树+均摊思想】UOJ #228 基础数据结构练习题
- Codeforces 12D (线段树 树状数组
- codeforces 46D 线段树 区间合并
- Codeforces 19D Points 线段树+set
- 【CodeForces】343D Water Tree 线段树
- codeforces 46D 线段树区间合并
- Points - CodeForces 19 D 线段树
- 【CodeForces】19D Points 线段树+set
- Codeforces 46D Parking Lot(线段树)
- 2017-03-24
- 问题4--centos怎么设置时间与另一台服务器时间同步
- CF 787A
- js中的事件委托技术
- JAVA内部类的一些总结
- 线段树操作中的一些预判方法【UOJ 228】【codeforces 438D】
- 问题5--zabbix数据库连接问题
- 浅谈Java中的对象和对象引用
- ZooKeeper 学习笔记一:常用命令
- VS2012串口助手编程C++
- 洛谷 P1336 最佳课题选择
- Linux安装JDK、Tomcat步骤
- 问题6--内网可以连接,无法访问外网
- 洛谷 1345_奶牛的电信Telecowmunication_网络流