省选集训杂题乱写
碎碎念
不去做专题做这个是吧?😓
闲的没事的时候写的,别D【叠甲】。
所以有人解释一下我的fhq合并为什么T了嘛?(详见 Nauuo and Bug 这道题)
没啥意义的就不放里面了。
「ALFR Round 3」C 割
贪心,发现最后的答案为
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; const int N = 2e5 + 10; int n,k;char s[N]; set<int> st[27]; signed main(){ srand(time(0)); cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>k>>(s+1); rep(i,1,n,1) st[s[i]-'a'+1].insert(i); drep(i,26,1,1){ if(!st[i].size()) continue; if(k > st[i].size()) cout<<(char)(i-1+'a')<<'\n',exit(0); else{ int len = st[i].size(); int num = ceil(1.0*len/k); rep(j,1,num,1) cout<<(char)(i-1+'a'); if(len % k != 0) return 0; vector<char> sta; for(int j = *st[i].rbegin() + 1;j <= n; ++j){ while(sta.size() && sta.back() < s[j]) sta.pop_back(); sta.push_back(s[j]); } for(auto i:sta) cout<<i; exit(0); } } }
[Ynoi2018] 五彩斑斓的世界
第二分块,均摊复杂度挺有意思的,剩下的和第一分块没啥区别啊,我调了大概3小时就过了。
发现每块的最大值总是不增的,考虑如何让这个复杂度均摊。假设当前块的最大值为
,那么将 的数合并到 上(就是减 )。 ,那么将 统一加 ,并打上整块减标记。
合并的话和第一分块一样,并查集维护即可。
证明
考虑证明这个复杂度,下面直接令并查集的复杂度为常数了。
对于第一种操作,我们用了
对于第二种操作,我们用了
由于最大值单调,所以总的时间复杂度均摊为
剩下的就和第一分块一样,发现本题卡空间,但是块与块之间没有关联,且答案可加,将询问离线逐块处理即可。总的时间复杂度
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; const int N = 1e6 + 10,M = 5e5 + 10,SN = 1010,VN = 1e5 + 10,V = 1e5 + 1,inf = 0x3f3f3f3f; int n,m,a[N],L[SN],R[SN],len,siz; int rt[VN],sz[VN],ans[M]; struct Query{int id,l,r,x;}q[M]; struct DSU{ vector<int> fa; void init(int n){fa.resize(n+1);rep(i,1,n,1) fa[i] = i;} int get_fa(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;} void Merge(int x,int y){ x = get_fa(x);y = get_fa(y); if(x == y) return ; if(x < y) swap(x,y);fa[x] = y; } }D; void Merge(int x,int y){ if(rt[y]) D.Merge(rt[x],rt[y]),a[D.get_fa(rt[x])] = y,rt[y] = D.get_fa(rt[y]); else rt[y] = rt[x],a[rt[y]] = y; sz[y] += sz[x];rt[x] = sz[x] = 0; } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m;rep(i,1,n,1) cin>>a[i]; rep(i,1,m,1) cin>>q[i].id>>q[i].l>>q[i].r>>q[i].x; D.init(n);len = sqrt(n);siz = n / len; rep(i,1,siz,1) L[i] = R[i - 1] + 1,R[i] = i*len; if(R[siz] < n) siz++,L[siz] = R[siz-1] + 1,R[siz] = n; rep(now,1,siz,1){ int mx = 0,tag = 0; memset(rt,0,sizeof rt);memset(sz,0,sizeof sz); int sl = L[now],sr = R[now]; rep(i,sl,sr,1){ int x = a[i];mx = max(mx,x); if(!rt[x]) rt[x] = i; else D.fa[i] = rt[x]; sz[x]++; } auto upd = [&](int x){ if(mx-tag > x*2){ drep(i,tag+x,tag+1,1) if(rt[i]) Merge(i,i+x); tag += x; } else{ drep(i,mx,tag+x+1,1) if(rt[i]) Merge(i,i-x); mx = min(mx,tag + x); } }; auto rbuild = [&](int l,int r,int x){ rep(i,sl,sr,1) a[i] = a[D.get_fa(i)]; rep(i,sl,sr,1) rt[a[i]] = 0,sz[a[i]] = 0; rep(i,l,r,1) if(a[i] - tag > x) a[i] -= x; rep(i,sl,sr,1) rt[a[i]] = 0,sz[a[i]] = 0; mx = 0; rep(i,sl,sr,1){ int x = a[i]; mx = max(mx,x); if(!rt[x]) rt[x] = i,D.fa[i] = i; else D.fa[i] = rt[x]; sz[x]++; } }; rep(i,1,m,1){ auto [id,l,r,x] = q[i]; if(r < sl || l > sr) continue; if(id == 1){ if(mx - tag <= x) continue; if(l <= sl && r >= sr) upd(x); else rbuild(max(l,sl),min(r,sr),x); } else{ if(l <= sl && r >= sr) ans[i] += sz[x+tag]; else rep(now,max(l,sl),min(r,sr),1) if(a[D.get_fa(now)]-tag == x) ans[i]++; } } } rep(i,1,m,1) if(q[i].id == 2) cout<<ans[i]<<'\n'; }
牛场围栏
同余最短路板子,注意不要重复建边。
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; const int N = 3010; int n,m,x[N],mn = 0x3f3f3f3f; vector<pair<int,int> > e[N]; set<int> used; bitset<N> vis; ll dist[N]; void dijkstra(int s){ memset(dist,0x3f,sizeof dist); priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q; q.emplace(0,0);dist[0] = 0; while(q.size()){ int x = q.top().second;q.pop(); if(vis[x]) continue; vis[x] = true; for(auto [y,w]:e[x]){ if(dist[y] > dist[x] + w){ dist[y] = dist[x] + w; q.emplace(dist[y],y); } } } } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m; rep(i,1,n,1){cin>>x[i];if(x[i] <= m + 1) cout<<-1,exit(0);mn = min(mn,x[i]);} mn -= m; rep(i,1,n,1) rep(j,x[i]-m,x[i],1){ if(j == mn || used.count(j)) continue; used.insert(j); rep(k,0,mn-1,1) e[k].emplace_back((k+j)%mn,j); } dijkstra(0); ll ans = 0; rep(i,0,mn-1,1){ // cerr<<dist[i]<<' '; if(dist[i] == 0x3f3f3f3f3f3f3f3f) cout<<-1,exit(0); ans = max(ans,dist[i]-mn); } cout<<ans<<'\n'; }
[Ynoi2006] rldcot
枚举LCA是显然的。
假如
。
对于第二个条件,假如
那么,贪心的,可以得出一个结论,讨论一个点
统计一个节点子树的问题,考虑DSU On Tree,用一个set维护重儿子的节点,然后遍历轻儿子,将轻儿子子树内的每个节点先找出前驱后继,然后再将其插入,可以保证不重不漏,时间复杂度
接下来的操作就是离线+扫描线了,
总时间复杂度
输入输出比较大,加上快读快写。
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; 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<<26,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qistream(FILE*_fp=stdin):fp(_fp),p(0){fread_unlocked(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread_unlocked(buf+SIZE-p,1,p,fp),p=0;}qistream&operator>>(char&str){str=getch();while(isspace(str))str=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(){return buf[p++];}qistream&operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();for(int i=0;ch>' ';++i,ch=getch())str[i]=ch;return*this;}}qcin(Fin); class qostream{static const size_t SIZE=1<<26,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qostream(FILE*_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite_unlocked(buf,1,p,fp);}void flush(){fwrite_unlocked(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)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;}}qcout(Fout); }using namespace IO; #define cin qcin #define cout qcout const int N = 1e5 + 10; struct BIT{ int mx,t[N]; int lb(int x){return (x&(-x));} void upd(int pos,int val){rep(i,pos,mx,lb(i)) t[i] += val;} int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += t[i];return res;} }bit; struct Point{ int l,val; Point(){}Point(int L,int V):l(L),val(V){} };vector<Point> vec[N]; struct Po{int l,r;Po(int L = 0,int R = 0):l(L),r(R){}}ct[N]; vector<pair<int,int> > e[N],q[N];set<int> st; int n,m,siz[N],son[N],fa[N],ans[N*5];ll dist[N]; void dfs1(int x){ siz[x] = 1; for(auto [y,w]:e[x]){ if(y == fa[x]) continue; dist[y] = dist[x] + w;fa[y] = x; dfs1(y);siz[x] += siz[y]; if(siz[son[x]] < siz[y]) son[x] = y; } } int hugeson; void Del(int x){ st.erase(x); for(auto [y,w]:e[x]) if(y != fa[x]) Del(y); } void Add(int x){ st.insert(x); for(auto [y,w]:e[x]) if(y != fa[x]) Add(y); } void Ins(int x,int f){ auto it = st.insert(x).first; if(it != st.begin()){ it--; int a = *it,b = x; if(a > b) swap(a,b); vec[b].emplace_back(a,dist[f]); it++; } it++; if(it != st.end()){ int a = *it,b = x; if(a > b) swap(a,b); vec[b].emplace_back(a,dist[f]); } st.erase(x); for(auto [y,w]:e[x]) if(y != fa[x]) Ins(y,f); } void dfs(int x){ vec[x].emplace_back(x,dist[x]); for(auto [y,w]:e[x]){ if(y == fa[x] || y == son[x]) continue; dfs(y);Del(y); } if(!son[x]) return st.insert(x),void(); dfs(son[x]); for(auto [y,w]:e[x]){ if(y == fa[x] || y == son[x]) continue; Ins(y,x);Add(y); } st.insert(x); } signed main(){ // cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m;bit.mx = n; rep(i,2,n,1){ int u,v,w;cin>>u>>v>>w; e[u].emplace_back(v,w);e[v].emplace_back(u,w); } rep(i,1,m,1){int l,r;cin>>l>>r;q[r].emplace_back(l-1,i);} rep(i,1,n,1) sort(q[i].begin(),q[i].end()); dfs1(1); vector<ll> num; rep(i,1,n,1) num.emplace_back(dist[i]); num.emplace_back(-0x3f3f3f3f3f3f3f3f); sort(num.begin(),num.end());num.erase(unique(num.begin(),num.end()),num.end()); rep(i,1,n,1) dist[i] = lower_bound(num.begin(),num.end(),dist[i]) - num.begin(); dfs(1); rep(now,1,n,1){ for(auto [l,val]:vec[now]){ if(!ct[val].l) ct[val] = Po(l,now),bit.upd(l,1); else{ if(l < ct[val].l) continue; bit.upd(ct[val].l,-1); bit.upd(l,1);ct[val] = Po(l,now); } } int res = bit.qry(now); for(auto [l,id]:q[now]){ ans[id] += res; ans[id] -= bit.qry(l); } } rep(i,1,m,1) cout<<ans[i]<<'\n'; }
[Ynoi Easy Round 2023] TEST_69
考虑一个数取
其实就是快速判断区间内是否所有的数都是
但是值域很大,lcm也可能很大,要打高精嘛?显然如果
时间复杂度
虽然但是还是没有理解对long long
存,详见这篇讨论
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; using i128 = __int128_t; const int N = 2e5 + 10;const ll V = 1e18; int n,m;ull a[N]; i128 gcd(i128 a,i128 b){return b==0?a:gcd(b,a%b);} i128 LCM(i128 a, i128 b){ if(a == -1 || b == -1) return -1; i128 gd = gcd(a,b),lm = a/gd*b; if(lm > V) return -1; return lm; } struct Segment_Tree{ struct segment_tree{int l,r;i128 lcm;unsigned sum;}t[N<<2]; #define l(x) t[x].l #define r(x) t[x].r #define lcm(x) t[x].lcm #define sum(x) t[x].sum void P(int k){ int ls = k<<1,rs = k<<1|1; lcm(k) = LCM(lcm(ls),lcm(rs)); sum(k) = sum(ls) + sum(rs); } void B(int k,int l,int r){ l(k) = l,r(k) = r; if(l == r) return sum(k) = lcm(k) = a[l],void(); int mid = (l + r) >> 1; B(k<<1,l,mid);B(k<<1|1,mid+1,r);P(k); } void upd(int k,int l,int r,i128 val){ if(lcm(k) != -1 && val%lcm(k) == 0) return; if(l(k) == r(k)) return sum(k) = lcm(k) = gcd(lcm(k),val),void(); int mid = (l(k) + r(k)) >> 1; if(l <= mid) upd(k<<1,l,r,val); if(r > mid) upd(k<<1|1,l,r,val); P(k); } unsigned qry(int k,int l,int r){ if(l <= l(k) && r(k) <= r) return sum(k); int mid = (l(k) + r(k)) >> 1;unsigned res = 0; if(l <= mid) res += qry(k<<1,l,r); if(r > mid) res += qry(k<<1|1,l,r); return res; } }sgt; signed main(){ cin>>n>>m;rep(i,1,n,1) cin>>a[i];sgt.B(1,1,n); rep(test,1,m,1){ int op,l,r;ll val; cin>>op>>l>>r; if(op == 1) cin>>val,sgt.upd(1,l,r,val); else cout<<sgt.qry(1,l,r)<<'\n'; } }
Nauuo and Bug
这不板子吗,这也配*3300?
函数复合+值域有交线段树合并。
但是正常写fhq合并在值域很小的时候TLE了,有人能解释一下嘛。
这两篇代码唯一的区别在 Join
函数中。
TLE On V is small
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; #define int ll const int N = 1e6 + 10; int n,m,p,a[N],tid[N],ans[N],st[N]; vector<int> Ad[N],De[N]; struct FHQ_Treap{ struct node{ int ls,rs,siz,fa,pri;ll val,lz; node(int L,int R,int S,int F,ll V,int P,ll Z): ls(L),rs(R),siz(S),fa(F),val(V),pri(P),lz(Z){}; };vector<node> t; #define ls(x) t[x].ls #define rs(x) t[x].rs #define siz(x) t[x].siz #define fa(x) t[x].fa #define val(x) t[x].val #define pri(x) t[x].pri #define lz(x) t[x].lz #define eb emplace_back int tot,rt; FHQ_Treap(){tot = 0,rt = 0;t.eb(0,0,0,0,0,0,0);} int New(int val){t.eb(0,0,1,0,val,rand(),0);tot++;return tot;} void P(int p){ siz(p) = siz(ls(p)) + siz(rs(p)) + 1; fa(p) = 0; if(ls(p)) fa(ls(p)) = p; if(rs(p)) fa(rs(p)) = p; } void mk(int p,ll val){if(!p) return;val(p) += val;lz(p) += val;} void D(int p){if(lz(p)) mk(ls(p),lz(p)),mk(rs(p),lz(p)),lz(p) = 0;} void split(int p,int 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){ if(!x || !y) return x|y; D(x);D(y); if(pri(x) > pri(y)) swap(x,y); int a,b;split(y,val(x),a,b); ls(x) = Join(ls(x),a); rs(x) = Join(rs(x),b); return P(x),x; } int Insert(int val){ int x,y;split(rt,val,x,y); int id = New(val); rt = Merge(Merge(x,id),y); return id; } ll get(int id){ int num = 0; for(;st[++num] = id;id = fa(id)); for(;num;D(st[num--])); return val(st[1]); } void upd(int val){ int x,y;mk(rt,val);split(rt,p-1,x,y);mk(y,-p);rt = Join(x,y); } #undef ls #undef rs #undef siz #undef fa #undef val #undef pri #undef lz #undef eb }fhq; pair<int,int> qry[N]; signed main(){ cin.tie(nullptr)->sync_with_stdio(false); srand(time(0)); cin>>n>>m>>p;rep(i,1,n,1) cin>>a[i]; rep(i,1,m,1){ int l,r;cin>>l>>r; Ad[l].emplace_back(i); De[r].emplace_back(i); } rep(i,1,n,1){ for(auto id:Ad[i]) tid[id] = fhq.Insert(0); fhq.upd(a[i]); for(auto id:De[i]) ans[id] = fhq.get(tid[id]); } rep(i,1,m,1) cout<<ans[i]<<'\n'; }
AC code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; #define int ll const int N = 2e6 + 10; int n,m,p,a[N],tid[N],ans[N],st[N]; vector<int> Ad[N],De[N]; mt19937 rnd(24320); struct FHQ_Treap{ struct node{ int ls,rs,siz,fa,pri;ll val,lz; node(int L,int R,int S,int F,ll V,int P,ll Z): ls(L),rs(R),siz(S),fa(F),val(V),pri(P),lz(Z){}; };vector<node> t; #define ls(x) t[x].ls #define rs(x) t[x].rs #define siz(x) t[x].siz #define fa(x) t[x].fa #define val(x) t[x].val #define pri(x) t[x].pri #define lz(x) t[x].lz #define eb emplace_back int tot,rt; FHQ_Treap(){tot = 0,rt = 0;t.eb(0,0,0,0,0,0,0);} int New(int val){t.eb(0,0,1,0,val,rand(),0);tot++;return tot;} void P(int p){ siz(p) = siz(ls(p)) + siz(rs(p)) + 1;fa(p) = 0; if(ls(p)) fa(ls(p)) = p;if(rs(p)) fa(rs(p)) = p; } void mk(int p,ll val){if(!p) return;val(p) += val;lz(p) += val;} void D(int p){if(lz(p)) mk(ls(p),lz(p)),mk(rs(p),lz(p)),lz(p) = 0;} void split(int p,int 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){ if(!x || !y) return x|y; int rt = 0,a; while(y){ a = y,D(a); while(ls(a)) a = ls(a),D(a); split(x,val(a),a,x); rt = Merge(rt,a); swap(x,y); } rt = Merge(rt,x); return rt; } int Insert(int val){ int x,y,id;split(rt,val,x,y); id = New(val),rt = Merge(Merge(x,id),y); return id; } ll get(int id){ int num = 0;for(;st[++num] = id;id = fa(id)); for(;num;D(st[num--]));return val(st[1]); } void upd(int val){ int x,y;mk(rt,val);split(rt,p-1,x,y);mk(y,-p);rt = Join(x,y); } #undef ls #undef rs #undef siz #undef fa #undef val #undef pri #undef lz #undef eb }fhq; pair<int,int> qry[N]; signed main(){ cin.tie(nullptr)->sync_with_stdio(false); srand(time(0)); cin>>n>>m>>p;rep(i,1,n,1) cin>>a[i]; rep(i,1,m,1){ int l,r;cin>>l>>r; Ad[l].emplace_back(i); De[r].emplace_back(i); } rep(i,1,n,1){ for(auto id:Ad[i]) tid[id] = fhq.Insert(0); fhq.upd(a[i]); for(auto id:De[i]) ans[id] = fhq.get(tid[id]); } rep(i,1,m,1) cout<<ans[i]<<'\n'; }
Special Segments of Permutation
以区间最大值为分治中心分治,启发式合并即可。
时间复杂度
code
#include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; const int N = 2e5 + 10; int n,a[N],lg[N],ct[N];ll ans = 0; pair<int,int> st[18][N]; int qry(int l,int r){int k = lg[r-l+1];return max(st[k][l],st[k][r-(1<<k)+1]).second;} void work(int l,int r,bool keep){ if(l > r) return; if(l == r){if(keep) ct[a[l]]++;return;} int mid = qry(l,r),mx = a[mid]; int len1 = mid-l,len2 = r-mid; if(len1 > len2) work(mid+1,r,false),work(l,mid-1,true); else work(l,mid-1,false),work(mid+1,r,true); if(len1 > len2) rep(i,mid+1,r,1) ans += ct[mx-a[i]]; else rep(i,l,mid-1,1) ans += ct[mx-a[i]]; if(!keep){ if(len1 > len2) rep(i,l,mid-1,1) ct[a[i]]--; else rep(i,mid+1,r,1) ct[a[i]]--; } else{ ct[mx]++; if(len1 > len2) rep(i,mid+1,r,1) ct[a[i]]++; else rep(i,l,mid-1,1) ct[a[i]]++; } } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cin>>n;rep(i,1,n,1) cin>>a[i],st[0][i] = {a[i],i}; rep(i,2,n,1) lg[i] = lg[i >> 1] + 1; rep(j,1,lg[n],1) rep(i,1,n-(1<<j)+1,1) st[j][i] = max(st[j-1][i],st[j-1][i+(1<<(j-1))]); work(1,n,false); cout<<ans<<'\n'; }
[Ynoi2011] ODT
Ynoi最水的一集。
套路的,将树进行重链剖分,然后对于每个节点维护一颗平衡树,维护其轻儿子的点权。
时间复杂度
code
#include<bits/stdc++.h> #include<bits/extc++.h> using namespace std; using namespace __gnu_pbds; #define rep(i,s,t,p) for(int i = s;i <= t;i += p) #define drep(i,s,t,p) for(int i = s;i >= t;i -= p) #ifdef LOCAL auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout); #else auto I = stdin,O = stdout; #endif using ll = long long;using ull = unsigned long long; using db = long double;using ldb = long double; namespace IO{ #define gc getchar_unlocked #define pc putchar_unlocked struct IO{ template<class T> inline void read(T &x){ char s = gc();x = 0; for(;s < '0' || s > '9';s = gc()); for(;'0' <= s && s <= '9';s = gc()) x = (x<<1)+(x<<3)+(s^48); } template<class T,class... Args> inline void read(T &x,Args&... argc){read(x);read(argc...);} template<class T> inline void write(T x){ static int sta[30],top;top = 0; do sta[++top] = x%10;while(x /= 10); while(top) pc(sta[top--]+'0'); } inline void write(char x){pc(x);} template<class T,class... Args> inline void write(T x,Args... argc){write(x);write(argc...);} }io; }using IO::io; #define read io.read #define write io.write #define pii pair<int,int> #define mk make_pair const int N = 1e6 + 10; int n,m,a[N],top[N],siz[N],son[N],fa[N],dep[N],dfn[N],rdfn[N],tim; vector<int> e[N]; tree<pii,null_type,less<pii>,rb_tree_tag,tree_order_statistics_node_update> bst[N]; void dfs1(int x){ dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(auto y:e[x]){ if(y == fa[x]) continue; fa[y] = x;dfs1(y); siz[x] += siz[y]; if(siz[son[x]] < siz[y]) son[x] = y; } } void dfs2(int x,int t){ top[x] = t;rdfn[dfn[x] = ++tim] = x; if(son[x]) dfs2(son[x],t);else return; for(auto y:e[x]){ if(y == fa[x] || y == son[x]) continue; bst[x].insert(mk(a[y],y));dfs2(y,y); } } struct BIT{ int mx,t[N];int lb(int x){return (x&(-x));} void upd(int pos,int val){rep(i,pos,mx,lb(i)) t[i] += val;} void upd(int l,int r,int val){upd(l,val);upd(r+1,-val);} int qry(int pos){int res = 0;drep(i,pos,1,lb(i)) res += t[i];return res;} }bit; void upd(int x,int y,int val){ if(!val) return; int fx = top[x],fy = top[y]; while(fx ^ fy){ if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy); int rx = x; x = fa[fx]; bst[x].erase(mk(a[fx] + bit.qry(dfn[fx]),fx)); bit.upd(dfn[fx],dfn[rx],val); bst[x].insert(mk(a[fx] + bit.qry(dfn[fx]),fx)); fx = top[x]; } if(dep[x] > dep[y]) swap(x,y); if(x == top[x] && fa[x]){ fx = x; x = fa[fx]; bst[x].erase(mk(a[fx] + bit.qry(dfn[fx]),fx)); bit.upd(dfn[fx],dfn[y],val); bst[x].insert(mk(a[fx] + bit.qry(dfn[fx]),fx)); } else bit.upd(dfn[x],dfn[y],val); } int qry(int x,int k){ int q1 = bit.qry(dfn[x]),q2 = bit.qry(dfn[fa[x]]),q3 = bit.qry(dfn[son[x]]); bst[x].insert(mk(a[x]+q1,x)); if(fa[x]) bst[x].insert(mk(a[fa[x]]+q2,fa[x])); if(son[x]) bst[x].insert(mk(a[son[x]]+q3,son[x])); int res = (*bst[x].find_by_order(k-1)).first; //for(auto [val,id]:bst[x]) cerr<<val<<' '<<id<<'\n'; bst[x].erase(mk(a[x]+q1,x)); if(fa[x]) bst[x].erase(mk(a[fa[x]]+q2,fa[x])); if(son[x]) bst[x].erase(mk(a[son[x]]+q3,son[x])); return res; } signed main(){ read(n,m);rep(i,1,n,1) read(a[i]); rep(i,2,n,1){int u,v;read(u,v);e[u].emplace_back(v);e[v].emplace_back(u);} dfs1(1);dfs2(1,1);bit.mx = n; rep(test,1,m,1){ int op,x,y,z; read(op,x,y); if(op == 1){ read(z);upd(x,y,z); } else{ write(qry(x,y),'\n'); } } }
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18634130
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】