1 条题解
-
0
自动搬运
来自洛谷,原作者为

CuFeO4
予我最狂热的孤独搬运于
2025-08-24 23:08:55,当前版本为作者最后更新于2025-02-04 17:03:20,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
插入标记回收板子。
将询问离线,用一颗值域上的平衡树维护,做扫描线,对于一个形如 的询问,在扫到 时将 插入,在扫完 时将其回收。
然后进行操作,假如当前扫到了 ,那么就是将平衡树中小于 的乘上 再加上 ,其余的不变。然后再将平衡树合并起来,用到值域有交平衡树合并。
对于回收时,特别地,记录一下平衡树每个节点的父亲,回收时将其到根的链提出来,然后从顶往下
pushdown即可。本题的一些细节:
- 开
long long。 - 打区间乘 标记时,记得交换左右儿子。
- 平衡树合并时,合并权值相同的节点,否则复杂度时错误的。
- 只要平衡树合并复杂度正确,本题就不怎么卡常。
#include<bits/stdc++.h> using namespace std; namespace IO { #ifdef LOCAL FILE*Fin(fopen("in.in","r")),*Fout(fopen("out.out","w")); #else FILE*Fin(stdin),*Fout(stdout); #endif class qistream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qistream(FILE*_fp=stdin):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;}qistream&operator>>(char&x){x=getch();while(isspace(x))x=getch();return*this;}template<class T>qistream&operator>>(T&x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=x*10+buf[p]-'0';x=flag?-x:x;return*this;}char getch(){p+BLOCK>=SIZE?flush():void();return buf[p++];}qistream&operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();int i=0;for(;ch>' ';++i,ch=getch())str[i]=ch;str[i]='\0';return*this;}}qcin(Fin); class qostream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qostream(FILE*_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream&operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=-x,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while(x);for(int i=0,j=len-1;i<j;++i,--j)std::swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream&operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}qostream&operator<<(const char*s){for(int i=0;s[i];++i)putch(s[i]);return*this;}}qcout(Fout); } using ll = long long; const int N = 2e5 + 10,M = 2e5 + 10; int n,m,p,tid[M],st[100],idx[M]; ll ans[M],a[N]; int Find(int x) { return x == idx[x] ? x : idx[x] = Find(idx[x]); } mt19937 rd(24320); vector<int> De[N]; vector<pair<int,ll> > Ad[N]; struct node{ int ls,rs,cn,siz,fa,pri; ll val,lz1,lz2; } t[M]; #define ls(x) t[x].ls #define rs(x) t[x].rs #define cn(x) t[x].cn #define siz(x) t[x].siz #define fa(x) t[x].fa #define pri(x) t[x].pri #define val(x) t[x].val #define lz1(x) t[x].lz1 #define lz2(x) t[x].lz2 int tot,rt; inline int New(ll val){t[++tot] = {0,0,1,1,0,(int)rd(),val,0,1}; return idx[tot]=tot;} inline void P(int p){ siz(p) = siz(ls(p)) + siz(rs(p)) + cn(p); fa(p) = 0; if(ls(p)) fa(ls(p)) = p; if(rs(p)) fa(rs(p)) = p; } inline void mk1(int p,ll val){if(p) val(p) += val,lz1(p) += val;} inline void mk2(int p,ll val){if(p) val(p) *= -1,lz1(p) *= -1,lz2(p) *= -1;} inline void D(int p){ if(lz2(p) != 1) mk2(ls(p),lz2(p)),mk2(rs(p),lz2(p)),swap(ls(p),rs(p)),lz2(p) = 1; if(lz1(p)) mk1(ls(p),lz1(p)),mk1(rs(p),lz1(p)),lz1(p) = 0; } void split(int p,ll val,int &x,int &y){ if(!p) return x = y = 0,void(); D(p); if(val(p) <= val) x = p,split(rs(p),val,rs(x),y); else y = p,split(ls(p),val,x,ls(y)); P(p); } int Merge(int x,int y){ if(!x || !y) return x|y; if(pri(x) < pri(y)) return D(x),rs(x) = Merge(rs(x),y),P(x),x; else return D(y),ls(y) = Merge(x,ls(y)),P(y),y; } int Join(int x, int y) { // x <- y if (!x || !y) return x | y; // 有一个空的即可返回 if (pri(x) > pri(y)) swap(x, y); // 取随机权值小的作为根 D(x);D(y); int L1 = ls(x), R1 = rs(x), L2 = 0, R2 = 0, equ = 0; // x 直接是左右子树 split(y, val(x), L2, R2), split(L2, val(x) - 1, L2, equ); // y 按权值 split if (equ) cn(x) += siz(equ), siz(x) += siz(equ), idx[equ] = x; // 相等特殊处理 ls(x) = Join(L1, L2), rs(x) = Join(R1, R2); // 递归合并 return P(x), x; // 更新信息 } inline int Insert(ll v) { int pl = 0, pm = 0, pr = 0; split(rt, v, pl, pr), split(pl, v - 1, pl, pm); pm ? (++cn(pm), ++siz(pm)) : pm = New(v); return rt = Merge(Merge(pl, pm), pr), pm; } inline ll get(int id){ int num = 0; for(;id && (st[++num] = id);id = fa(id)); if (int y = Find(st[num]); y != st[num]) for (id = y, num = 0;id && (st[++num] = id);id = fa(id)); for (int i = num; i > 1; D(st[i--])); return val(st[1]); } inline void upd(ll val){ int x = 0,y = 0; split(rt,floor(val/2.0),x,y); mk2(x,-1);mk1(x,val); rt = Join(x,y); } void print(int x){ D(x); cerr<<x<<": "<<val(x)<<' '<<fa(x)<<'\n'; if(ls(x)) print(ls(x)); if(rs(x)) print(rs(x)); } signed main(){ //cin.tie(nullptr)->sync_with_stdio(false); IO::qcin>>n>>m; for (int i = 1; i <= n; i++) IO::qcin>>a[i]; for (int i = 1, l, r; i <= m; i++) { ll x; IO::qcin>>x>>l>>r; Ad[l].emplace_back(i,x); De[r].emplace_back(i); } for (int i = 1; i <= n; i++) { for(auto &[id,x]:Ad[i]) tid[id] = Insert(x); upd(a[i]); for(int &id:De[i]) ans[id] = get(tid[id]); //cerr<<i<<":::\n"; //print(rt); //cerr<<"\n"; } for (int i = 1; i <= m; i++) IO::qcout<<ans[i]<<'\n'; } - 开
- 1
信息
- ID
- 11397
- 时间
- 1500ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者