题解 混凝土粉末
考场上分块水过去了
先说分块:块内按y排序,处理边角的时候归并优化一下可以做到 \(O(n\sqrt n)\)
然后正解是树状数组扫描线
树状数组以操作编号为下标,存的是操作的h
每次询问在树状数组上二分找到第一个前缀和 \(\geqslant y\) 的位置
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF: *p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, q;
namespace force{
int tot;
struct cge{int l, r, x; ll h; inline void build(int a, int b, int c, ll d) {l=a; r=b; x=c; h=d;}}cge[N];
void solve() {
ll y;
for (int i=1,l,r,h,x; i<=q; ++i) {
if (read()&1) {
l=read(); r=read(); h=read();
cge[++tot].build(l, r, i, h);
}
else {
x=read(); y=read();
ll h=0;
for (int j=1; j<=tot; ++j) {
if (cge[j].l<=x&&cge[j].r>=x) {
h+=cge[j].h;
if (h>=y) {printf("%d\n", cge[j].x); goto jump;}
}
}
puts("0");
jump: ;
}
}
exit(0);
}
}
namespace task1{
int ans[N], op[N];
int bel[N], beg[N], len, lim;
ll tag[N];
struct cge{int l, r, x; ll h; inline void build(int a, int b, int c, ll d) {l=a; r=b; x=c; h=d;}}cg[N];
struct que{int x; ll y; inline void build(int a, ll b) {x=a; y=b;}}qu[N];
struct tpl{int x, rk; ll dlt; tpl(ll c, int a, int b) {x=a; rk=b; dlt=c;}};
inline bool operator < (tpl a, tpl b) {return a.dlt<b.dlt;}
vector<tpl> buc[1010];
void upd(int l, int r, int x, ll h) {
// cout<<"upd: "<<x<<endl;
int sid=bel[l], eid=bel[r];
if (sid==eid) {
if (!buc[sid].size()) return ;
for (int i=beg[sid]; i<buc[sid].size(); ++i) {
if (l<=buc[sid][i].x&&r>=buc[sid][i].x) {
buc[sid][i].dlt-=h;
if (buc[sid][i].dlt<=tag[sid]) {
ans[buc[sid][i].rk]=x;
swap(buc[sid][beg[sid]], buc[sid][i]);
++beg[sid];
}
}
}
stable_sort(buc[sid].begin()+beg[sid], buc[sid].end());
return ;
}
if (buc[sid].size()) {
for (int i=beg[sid]; i<buc[sid].size(); ++i) {
if (l<=buc[sid][i].x&&r>=buc[sid][i].x) {
buc[sid][i].dlt-=h;
if (buc[sid][i].dlt<=tag[sid]) {
ans[buc[sid][i].rk]=x;
swap(buc[sid][beg[sid]], buc[sid][i]);
++beg[sid];
}
}
}
stable_sort(buc[sid].begin()+beg[sid], buc[sid].end());
}
for (int i=sid+1; i<eid; ++i) if (buc[i].size()) {
tag[i]+=h;
for (int j=beg[i]; j<buc[i].size(); ++j) {
if (buc[i][j].dlt<=tag[i]) ++beg[i], ans[buc[i][j].rk]=x;
else break;
}
}
if (buc[eid].size()) {
for (int i=beg[eid]; i<buc[eid].size(); ++i) {
if (l<=buc[eid][i].x&&r>=buc[eid][i].x) {
buc[eid][i].dlt-=h;
if (buc[eid][i].dlt<=tag[eid]) {
ans[buc[eid][i].rk]=x;
swap(buc[eid][beg[eid]], buc[eid][i]);
++beg[eid];
}
}
}
stable_sort(buc[eid].begin()+beg[eid], buc[eid].end());
}
}
void solve() {
len=sqrt(n);
for (int i=1; i<=n; ++i) bel[i]=(i-1)/len+1, lim=max(lim, bel[i]);
ll y;
for (int i=1,l,r,h,x; i<=q; ++i) {
if ((op[i]=read())&1) {
l=read(); r=read(); h=read();
cg[i].build(l, r, i, h);
}
else {
x=read(); y=read();
qu[i].build(x, y);
buc[bel[x]].pb(tpl(y, x, i));
}
}
for (int i=1; i<=lim; ++i) sort(buc[i].begin(), buc[i].end());
for (int i=1; i<=q; ++i) {
if (op[i]&1) upd(cg[i].l, cg[i].r, i, cg[i].h);
else printf("%d\n", ans[i]);
}
exit(0);
}
}
signed main()
{
freopen("concrete.in", "r", stdin);
freopen("concrete.out", "w", stdout);
n=read(); q=read();
if (q<=2000) force::solve();
else task1::solve();
return 0;
}