[CFR512 div 2 F]Putting Boxes Together(线段树)

http://codeforces.com/blog/entry/62013

两个结论:

1.一定有一个箱子不用动。

2.不动的箱子一定是加权前缀和为S/2的那个。

1显然,2由1易得。

于是问题变为:求一段区间前缀和>S/2的第一个数的位置。显然先求出S/2,再线段树上二分即可,实现过程见代码。

自定义struct比stl:pair快,注意取模和爆long long的问题。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define ls (x<<1)
 4 #define rs (ls|1)
 5 #define lson ls,L,mid
 6 #define rson rs,mid+1,R
 7 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 8 typedef long long ll;
 9 using namespace std;
10
11 const int N=200010,inf=1e9,mod=1e9+7;
12 int n,Q,x,y,a[N],w[N];
13 struct Tr{ ll s1,s2; }v[N<<2];
14 struct P{ ll x,y; };
15
16 void upd(int x){ v[x].s1=v[ls].s1+v[rs].s1; v[x].s2=(v[ls].s2+v[rs].s2)%mod; }
17
18 void build(int x,int L,int R){
19     if (L==R){ v[x].s1=w[L]; v[x].s2=1ll*a[L]*w[L]%mod; return; }
20     int mid=(L+R)>>1;
21     build(lson); build(rson); upd(x);
22 }
23
24 void mdf(int x,int L,int R,int pos,int k){
25     if (L==R){ v[x].s1=k; v[x].s2=1ll*a[pos]*k%mod; return; }
26     int mid=(L+R)>>1;
27     if (pos<=mid) mdf(lson,pos,k); else mdf(rson,pos,k);
28     upd(x);
29 }
30
31 P que(int x,int L,int R,int l,int r){
32     if (L==l && r==R) return (P){v[x].s1,v[x].s2};
33     int mid=(L+R)>>1;
34     if (r<=mid) return que(lson,l,r);
35     else if (l>mid) return que(rson,l,r);
36         else{
37             P s1=que(lson,l,mid),s2=que(rson,mid+1,r);
38             return (P){s1.x+s2.x,(s1.y+s2.y)%mod};
39         }
40 }
41
42 P ask(int x,int L,int R,int l,int r,ll k){
43     if (L==l && r==R){
44         if (v[x].s1<=k) return (P){inf,v[x].s1};
45         if (L==R) return (P){l,0};
46     }
47     int mid=(L+R)>>1;
48     if (r<=mid) return ask(lson,l,r,k);
49     else if (l>mid) return ask(rson,l,r,k);
50         else{
51             ll sm=0,res=inf;
52             P cur=ask(lson,l,mid,k);
53             res=min(res,cur.x); sm+=cur.y;
54             if (res<inf) return (P){res,sm};
55             cur=ask(rson,mid+1,r,k-sm);
56             res=min(res,cur.x); sm+=cur.y;
57             return (P){res,sm};
58         }
59 }
60
61 int work(int l,int r){
62     int k=ask(1,1,n,l,r,que(1,1,n,l,r).x/2).x;
63     P t1=(k==l) ? (P){0,0} : que(1,1,n,l,k-1),t2=que(1,1,n,k,r);
64     return ((a[k]*(t1.x%mod)-t1.y+t2.y-a[k]*(t2.x%mod))%mod+mod)%mod;
65 }
66
67 int main(){
68     freopen("1058f.in","r",stdin);
69     freopen("1058f.out","w",stdout);
70     scanf("%d%d",&n,&Q);
71     rep(i,1,n) scanf("%d",&a[i]),a[i]=a[i]-i;
72     rep(i,1,n) scanf("%d",&w[i]);
73     build(1,1,n);
74     while (Q--){
75         scanf("%d%d",&x,&y);
76         if (x<0) mdf(1,1,n,-x,y); else printf("%d\n",work(x,y));
77     }
78     return 0;
79 }

原文地址:https://www.cnblogs.com/HocRiser/p/10351581.html

时间: 2024-11-06 09:41:50

[CFR512 div 2 F]Putting Boxes Together(线段树)的相关文章

codeforces round 512 F. Putting Boxes Together 树状数组维护区间加权平均数

F. Putting Boxes Together time limit per test 2.5 seconds memory limit per test 256 megabytes input standard input output standard output There is an infinite line consisting of cells. There are nn boxes in some cells of this line. The ii-th box stan

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Codeforces Round #310 (Div. 1) C. Case of Chocolate (线段树)

题目地址:传送门 这题虽然是DIV1的C..但是挺简单的..只要用线段树分别维护一下横着和竖着的值就可以了,先离散化再维护.每次查找最大的最小值<=tmp的点,可以直接在线段树里搜,也可以二分去找. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.

Codeforces Round #590 (Div. 3) D. Distinct Characters Queries(线段树, 位运算)

链接: https://codeforces.com/contest/1234/problem/D 题意: You are given a string s consisting of lowercase Latin letters and q queries for this string. Recall that the substring s[l;r] of the string s is the string slsl+1-sr. For example, the substrings

The 2019 ICPC China Nanchang National Invitational and International Silk-Road Programming Contest - F.Sequence(打表+线段树)

题意:给你一个长度为$n$的数组,定义函数$f(l,r)=a_{l} \oplus a_{l+1} \oplus...\oplus a_{r}$,$F(l,r)=f(l,l)\oplus f(l,l+1)\oplus ...\oplus f(l,r)\oplus f(l+1,l+1)\oplus ...f(l+1,r)\oplus ...\oplus f(r,r)$,有两种操作,第一种将数组中某个元素$a[x]$变为$y$,第二种计算$F(l,r)$的值. 思路:打表后发现只有当$l$和$r$同

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

Codeforces Round #225 (Div. 2)---E. Propagating tree(时间戳+线段树)

Iahub likes trees very much. Recently he discovered an interesting tree named propagating tree. The tree consists of n nodes numbered from 1 to n, each node i having an initial value ai. The root of the tree is node 1. This tree has a special propert

Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

D. Vika and Segments Vika has an infinite sheet of squared paper. Initially all squares are white. She introduced a two-dimensional coordinate system on this sheet and drew n black horizontal and vertical segments parallel to the coordinate axes. All

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long