<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【做題記錄】2025刷題計劃—數(shù)據(jù)結構1

      A. 【模板】線段樹分裂

      首先想到了 FHQ-Treap,但是合并的時候還需要滿足大小順序,不太好搞。考慮權值線段樹。
      \(1\)\(4\) 操作都是比較常規(guī)的。對于 \(0\) 操作,在 \(p\) 的線段樹上將 \([x,y]\) 這個區(qū)間拆成 \(O(\log n)\) 個區(qū)間,賦給新的線段樹。注意當找到區(qū)間時需要將 \(p\) 的線段樹上的信息清掉。
      時間復雜度分析,\(0\),\(2\)\(3\)\(4\) 操作單次的復雜度都是 \(O(\log n)\) 的,而所有的 \(1\) 操作時間復雜度之和不會超過總點數(shù),即 \(O((n+m)\log n)\)。所以時間復雜度就是 \(O((n+m)\log n)\)??臻g帶一個 \(2\) 的常數(shù)。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define ls(id) tr[id].ls
      #define rs(id) tr[id].rs
      #define sz(id) tr[id].sz
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      int n,m,rt[maxn],tot,cnt=1;
      struct{
      	int ls,rs;
      	ll sz;
      }tr[maxn*40];
      il void pushup(int id){
      	sz(id)=sz(ls(id))+sz(rs(id));
      }
      il void insert(int &id,int l,int r,int x,int v){
      	if(!id){
      		id=++tot;
      	}
      	if(l==r){
      		sz(id)+=v;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(x<=mid){
      		insert(ls(id),l,mid,x,v);
      	}
      	else{
      		insert(rs(id),mid+1,r,x,v);
      	}
      	pushup(id);
      }
      il int move(int &p,int L,int R,int l,int r){
      	if(!p){
      		return 0;
      	}
      	if(L>=l&&R<=r){
      		int q=p;
      		p=0;
      		return q;
      	}
      	int q=++tot,mid=(L+R)>>1;
      	if(l<=mid){
      		ls(q)=move(ls(p),L,mid,l,r);
      	}
      	if(r>mid){
      		rs(q)=move(rs(p),mid+1,R,l,r);
      	}
      	pushup(p),pushup(q);
      	return q;
      }
      il int merge(int p,int q,int l,int r){
      	if(!p||!q){
      		return p+q;
      	}
      	if(l==r){
      		sz(++tot)=sz(p)+sz(q);
      		return tot;
      	}
      	int x=++tot,mid=(l+r)>>1;
      	ls(x)=merge(ls(p),ls(q),l,mid);
      	rs(x)=merge(rs(p),rs(q),mid+1,r);
      	pushup(x);
      	return x;
      }
      il ll query(int id,int L,int R,int l,int r){
      	if(!id){
      		return 0;
      	}
      	if(L>=l&&R<=r){
      		return sz(id);
      	}
      	int mid=(L+R)>>1;
      	ll res=0;
      	if(l<=mid){
      		res+=query(ls(id),L,mid,l,r);
      	}
      	if(r>mid){
      		res+=query(rs(id),mid+1,R,l,r);
      	}
      	return res;
      }
      il int kth(int id,int l,int r,ll k){
      	if(l==r){
      		return l;
      	}
      	int mid=(l+r)>>1;
      	if(sz(ls(id))>=k){
      		return kth(ls(id),l,mid,k);
      	}
      	return kth(rs(id),mid+1,r,k-sz(ls(id)));
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1,v;i<=n;i++){
      		cin>>v;
      		insert(rt[1],1,n,i,v);
      	}
      	while(m--){
      		int opt;
      		cin>>opt;
      		switch(opt){
      			case 0:{
      				int p,l,r;
      				cin>>p>>l>>r;
      				rt[++cnt]=move(rt[p],1,n,l,r);
      				break;
      			}
      			case 1:{
      				int p,q;
      				cin>>p>>q;
      				rt[p]=merge(rt[p],rt[q],1,n);
      				rt[q]=0;
      				break;
      			}
      			case 2:{
      				int p,x,v;
      				cin>>p>>v>>x;
      				insert(rt[p],1,n,x,v);
      				break;
      			}
      			case 3:{
      				int p,l,r;
      				cin>>p>>l>>r;
      				cout<<query(rt[p],1,n,l,r)<<"\n";
      				break;
      			}
      			default:{
      				int p;
      				ll k;
      				cin>>p>>k;
      				if(sz(rt[p])<k){
      					cout<<"-1\n";
      				}
      				else{
      					cout<<kth(rt[p],1,n,k)<<"\n";
      				}
      				break;
      			}
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      B. 三元上升子序列

      考慮這個三元上升子序列,可以拆成兩個二元來做。
      考慮 FHQ-Treap,依次插入 \(a_i\),將當前的平衡樹按 \(a_i-1\) 分裂后左子樹的大小就是以 \(a_i\) 結尾的二元上升子序列數(shù),記為 \(num\)。而左子樹的 \(num\) 之和就是以 \(a_i\) 結尾的三元上升子序列數(shù)了。時間復雜度 \(O(n\log n)\)。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=3e4+5;
      int n,rt,tot,sz[maxn];
      int ls[maxn],rs[maxn];
      int zhi[maxn],jan[maxn];
      ll num[maxn],sum[maxn];
      il void pushup(int id){
      	sum[id]=sum[ls[id]]+sum[rs[id]]+num[id];
      	sz[id]=sz[ls[id]]+sz[rs[id]]+1;
      }
      il int merge(int p,int q){
      	if(!p||!q){
      		return p+q;
      	}
      	if(jan[p]<jan[q]){
      		rs[p]=merge(rs[p],q);
      		pushup(p);
      		return p;
      	}
      	ls[q]=merge(p,ls[q]);
      	pushup(q);
      	return q;
      }
      il void split(int id,int &p,int &q,int x){
      	if(!id){
      		p=q=0;
      		return ;
      	}
      	if(zhi[id]<=x){
      		p=id;
      		split(rs[id],rs[id],q,x);
      	}
      	else{
      		q=id;
      		split(ls[id],p,ls[id],x);
      	}
      	pushup(id);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	ll ans=0;
      	while(n--){
      		int v,x,y;
      		cin>>v;
      		split(rt,x,y,v-1);
      		ans+=sum[x];
      		zhi[++tot]=v;
      		num[tot]=sum[tot]=sz[x];
      		jan[tot]=rand();
      		sz[tot]=1;
      		rt=merge(merge(x,tot),y);
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      C. Sanae and Giant Robot

      csp2025-提高組并查集專題 E

      Code
      #include<bits/stdc++.h>
      #define int long long
      #define il inline
      #define pb push_back
      #define lwrb lower_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      int T,n,m;
      int a[maxn],b[maxn];
      vector<int> e[maxn];
      set<int> zero;
      queue<int> q;
      il void solve(){
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      	}
      	for(int i=1;i<=n;i++){
      		cin>>b[i];
      	}
      	while(m--){
      		int l,r;
      		cin>>l>>r;
      		l--;
      		e[l].pb(r),e[r].pb(l);
      	}
      	for(int i=1;i<=n;i++){
      		a[i]=a[i-1]+a[i]-b[i];
      	}
      	for(int i=0;i<=n;i++){
      		if(a[i]){
      			zero.insert(i);
      		}
      		else{
      			q.push(i);
      		}
      	}
      	while(q.size()){
      		int u=q.front();
      		q.pop();
      //	puts("666");
      		for(int v:e[u]){
      			if(a[v]){
      				continue;
      			}
      			int l=u,r=v;
      			if(l>r){
      				swap(l,r);
      			}
      			auto x=zero.lwrb(l);
      			while(x!=zero.end()&&*x<=r){
      				a[*x]=0;
      				q.push(*x);
      				x=zero.erase(x);
      			}
      		}
      	}
      	puts(zero.size()?"NO":"YES");
      	zero.clear();
      	for(int i=0;i<=n;i++){
      		e[i].clear();
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      signed main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--){
      		solve();
      	}
      	return 0;
      }
      }
      signed main(){return asbt::main();}
      

      D. [COCI2010-2011#6] STEP

      線段樹,對于每個區(qū)間維護區(qū)間長度,最左端顏色,最右端顏色,緊貼左側的最長 01 串,緊貼右側的最長 01 串和區(qū)間內的最長 01 串。pushup 時考察左區(qū)間的右端顏色和右區(qū)間的左端顏色是否不同。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define lid id<<1
      #define rid id<<1|1
      #define len(id) tr[id].len
      #define lc(id) tr[id].lc
      #define rc(id) tr[id].rc
      #define lk(id) tr[id].lk
      #define rk(id) tr[id].rk
      #define mk(id) tr[id].mk
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      int n,m;
      struct node{
      	int len,lc,rc;
      	int lk,rk,mk;
      	il node operator+(const node &x)const{
      		node res;
      		res.len=len+x.len;
      		res.lc=lc,res.rc=x.rc;
      		res.lk=lk,res.rk=x.rk;
      		res.mk=max(mk,x.mk);
      		if(rc^x.lc){
      			res.mk=max(res.mk,rk+x.lk);
      			if(mk==len){
      				res.lk=max(res.lk,len+x.lk);
      			}
      			if(x.mk==x.len){
      				res.rk=max(res.rk,rk+x.len);
      			}
      		}
      		return res;
      	}
      }tr[maxn<<2];
      il void pushup(int id){
      	tr[id]=tr[lid]+tr[rid];
      }
      il void build(int id,int l,int r){
      	if(l==r){
      		len(id)=1;
      		lc(id)=rc(id)=0;
      		lk(id)=rk(id)=mk(id)=1;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(lid,l,mid);
      	build(rid,mid+1,r);
      	pushup(id);
      }
      il void upd(int id,int l,int r,int p){
      	if(l==r){
      		lc(id)^=1,rc(id)^=1;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(p<=mid){
      		upd(lid,l,mid,p);
      	}
      	else{
      		upd(rid,mid+1,r,p);
      	}
      	pushup(id);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	build(1,1,n);
      	while(m--){
      		int p;
      		cin>>p;
      		upd(1,1,n,p);
      		cout<<mk(1)<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      E. [USACO11DEC] Grass Planting G

      樹剖 + 線段樹,區(qū)間加單點查。可以標記永久化。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define lid id<<1
      #define rid id<<1|1
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5;
      int n,m,cnt,tr[maxn<<2];
      int fa[maxn],sz[maxn];
      int hes[maxn],dep[maxn];
      int top[maxn],dfn[maxn];
      vector<int> e[maxn];
      il void dfs1(int u){
      	sz[u]=1;
      	int mxs=0;
      	for(int v:e[u]){
      		if(v==fa[u]){
      			continue;
      		}
      		fa[v]=u,dep[v]=dep[u]+1;
      		dfs1(v);
      		sz[u]+=sz[v];
      		if(mxs<sz[v]){
      			mxs=sz[v],hes[u]=v;
      		}
      	}
      }
      il void dfs2(int u){
      	dfn[u]=++cnt;
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(int v:e[u]){
      		if(v==fa[u]||v==hes[u]){
      			continue;
      		}
      		dfs2(v);
      	}
      }
      il void upd(int id,int L,int R,int l,int r){
      //	cout<<l<<" "<<r<<"\n";
      	if(l>r){
      		return ;
      	}
      	if(L>=l&&R<=r){
      		tr[id]++;
      		return ;
      	}
      	int mid=(L+R)>>1;
      	if(l<=mid){
      		upd(lid,L,mid,l,r);
      	}
      	if(r>mid){
      		upd(rid,mid+1,R,l,r);
      	}
      }
      il int query(int id,int l,int r,int p){
      	int res=tr[id];
      	if(l==r){
      		return res;
      	}
      	int mid=(l+r)>>1;
      	if(p<=mid){
      		return res+query(lid,l,mid,p);
      	}
      	return res+query(rid,mid+1,r,p);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1,u,v;i<n;i++){
      		cin>>u>>v;
      		e[u].pb(v),e[v].pb(u);
      	}
      	dfs1(1),dfs2(1);
      	while(m--){
      		char opt;
      		int u,v;
      		cin>>opt>>u>>v;
      		if(opt=='P'){
      //			cout<<u<<" "<<v<<"\n";
      //	for(int i=1;i<=n;i++){
      //		cout<<top[i]<<" ";
      //	}
      //	puts("");
      //			cout<<top[u]<<" "<<top[v]<<"\n";
      			while(top[u]!=top[v]){
      //				puts("666");
      				if(dep[top[u]]<dep[top[v]]){
      					swap(u,v);
      				}
      //				cout<<u<<"\n";
      				upd(1,1,n,dfn[top[u]],dfn[u]);
      				u=fa[top[u]];
      			}
      //			cout<<u<<" "<<v<<"\n";
      			if(dep[u]>dep[v]){
      				swap(u,v);
      			}
      			upd(1,1,n,dfn[u]+1,dfn[v]);
      		}
      		else{
      			if(dep[u]<dep[v]){
      				swap(u,v);
      			}
      			cout<<query(1,1,n,dfn[u])<<"\n";
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      F. [NOI2021] 輕重邊

      對于每次修改,將這個路徑上的所有點都賦一個新的權值。于是兩端權值相等的就是重邊,不等的就是輕邊。樹剖 + 線段樹維護即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define lid id<<1
      #define rid id<<1|1
      #define lc(id) tr[id].lc
      #define rc(id) tr[id].rc
      #define num(id) tr[id].num
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5;
      int T,n,m,cnt,tag[maxn<<2];
      int sz[maxn],hes[maxn];
      int dep[maxn],top[maxn];
      int dfn[maxn],fa[maxn];
      vector<int> e[maxn];
      struct node{
      	int lc,rc,num;
      	il node operator+(const node &x)const{
      		node res;
      		res.lc=lc,res.rc=x.rc;
      		res.num=num+x.num;
      		if(rc==x.lc){
      			res.num++;
      		}
      		return res;
      	}
      }tr[maxn<<2];
      il void dfs1(int u){
      	sz[u]=1;
      	int mxs=0;
      	for(int v:e[u]){
      		if(v!=fa[u]){
      			fa[v]=u;
      			dep[v]=dep[u]+1;
      			dfs1(v);
      			sz[u]+=sz[v];
      			if(mxs<sz[v]){
      				hes[u]=v;
      				mxs=sz[v];
      			}
      		}
      	}
      }
      il void dfs2(int u){
      	dfn[u]=++cnt;
      	if(!top[u]){
      		top[u]=u;
      	}
      	if(hes[u]){
      		top[hes[u]]=top[u];
      		dfs2(hes[u]);
      	}
      	for(int v:e[u]){
      		if(v!=fa[u]&&v!=hes[u]){
      			dfs2(v);
      		}
      	}
      }
      il void pushup(int id){
      	tr[id]=tr[lid]+tr[rid];
      }
      il void pushtag(int id,int v,int len){
      	lc(id)=rc(id)=tag[id]=v;
      	num(id)=len-1;
      }
      il void pushdown(int id,int len){
      	if(tag[id]){
      		pushtag(lid,tag[id],(len+1)>>1);
      		pushtag(rid,tag[id],len>>1);
      		tag[id]=0;
      	}
      }
      il void build(int id,int l,int r){
      	tag[id]=0;
      	if(l==r){
      		pushtag(id,l,1);
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(lid,l,mid);
      	build(rid,mid+1,r);
      	pushup(id);
      }
      il void upd(int id,int L,int R,int l,int r,int v){
      	if(L>=l&&R<=r){
      		pushtag(id,v,R-L+1);
      		return ;
      	}
      	pushdown(id,R-L+1);
      	int mid=(L+R)>>1;
      	if(l<=mid){
      		upd(lid,L,mid,l,r,v);
      	}
      	if(r>mid){
      		upd(rid,mid+1,R,l,r,v);
      	}
      	pushup(id);
      }
      il node query(int id,int L,int R,int l,int r){
      	if(L>=l&&R<=r){
      		return tr[id];
      	}
      	pushdown(id,R-L+1);
      	int mid=(L+R)>>1;
      	if(r<=mid){
      		return query(lid,L,mid,l,r);
      	}
      	if(l>mid){
      		return query(rid,mid+1,R,l,r);
      	}
      	return query(lid,L,mid,l,r)+query(rid,mid+1,R,l,r);
      }
      il void solve(){
      	cin>>n>>m;
      	for(int i=1,u,v;i<n;i++){
      		cin>>u>>v;
      		e[u].pb(v),e[v].pb(u);
      	}
      	cnt=0;
      	dfs1(1),dfs2(1);
      //	for(int i=1;i<=n;i++){
      //		cout<<fa[i]<<" ";
      //	}
      //	puts("");
      	build(1,1,n);
      	int tot=n;
      	while(m--){
      		int opt,u,v;
      		cin>>opt>>u>>v;
      		if(opt==1){
      			tot++;
      			while(top[u]!=top[v]){
      				if(dep[top[u]]<dep[top[v]]){
      					swap(u,v);
      				}
      				upd(1,1,n,dfn[top[u]],dfn[u],tot);
      				u=fa[top[u]];
      			}
      			if(dep[u]>dep[v]){
      				swap(u,v);
      			}
      			upd(1,1,n,dfn[u],dfn[v],tot);
      		}
      		else{
      			node resu,resv;
      			bool flu=0,flv=0;
      			while(top[u]!=top[v]){
      				if(dep[top[u]]>dep[top[v]]){
      					if(!flu){
      						flu=1;
      						resu=query(1,1,n,dfn[top[u]],dfn[u]);
      					}
      					else{
      						resu=query(1,1,n,dfn[top[u]],dfn[u])+resu;
      					}
      					u=fa[top[u]];
      				}
      				else{
      					if(!flv){
      						flv=1;
      						resv=query(1,1,n,dfn[top[v]],dfn[v]);
      					}
      					else{
      						resv=query(1,1,n,dfn[top[v]],dfn[v])+resv;
      					}
      					v=fa[top[v]];
      				}
      			}
      			if(dep[u]<dep[v]){
      				if(!flv){
      					flv=1;
      					resv=query(1,1,n,dfn[u],dfn[v]);
      				}
      				else{
      					resv=query(1,1,n,dfn[u],dfn[v])+resv;
      				}
      			}
      			else{
      				if(!flu){
      					flu=1;
      					resu=query(1,1,n,dfn[v],dfn[u]);
      				}
      				else{
      					resu=query(1,1,n,dfn[v],dfn[u])+resu;
      				}
      			}
      			if(!flu){
      				cout<<resv.num<<"\n";
      			}
      			else if(!flv){
      				cout<<resu.num<<"\n";
      			}
      			else{
      				int res=resu.num+resv.num;
      				if(resu.lc==resv.lc){
      					res++;
      				}
      				cout<<res<<"\n";
      			}
      		}
      	}
      	for(int i=1;i<=n;i++){
      		e[i].clear();
      		sz[i]=hes[i]=dfn[i]=fa[i]=dep[i]=top[i]=0;
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--){
      		solve();
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      G. 「TOCO Round 1」History

      看到“回到 \(x\) 后的狀態(tài)”,顯然考慮可持久化線段樹。記開燈的為 \(1\),關燈的為 \(0\),對于每個詢問只需去查某些點的權值和即可。
      考慮怎么將符合條件的點轉化為區(qū)間。詢問的是同一深度的點,可以考慮 bfs 序??紤]如果 \(y\) 是奇數(shù),顯然答案為 \(0\);否則詢問的點就是 \(x\)\(\frac{y}{2}\) 級祖先在 \(x\) 這一層的后代,再去掉 \(x\)\(\frac{y}{2}-1\) 級祖先在 \(x\) 這一層的后代。考慮怎么去找到詢問對應的區(qū)間。對于同一棵子樹的同一深度,其 bfs 序是連續(xù)的。因此可以將詢問先存下來,對于每個節(jié)點建線段樹,存儲某一深度的 bfs 序最大值和最小值。線段樹合并即可。
      時間復雜度分析,處理操作時每次都為 \(O(\log n)\),所有線段樹合并的總時間復雜度為 \(O(n\log n)\),于是總的時間復雜度就為 \(O((n+m)\log n)\)。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      #define pii pair<int,int>
      #define mp make_pair
      #define fir first
      #define sec second
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=1e5+5;
      const int inf=0x3f3f3f3f;
      int n,m,dep[maxn];
      int anc[maxn][22];
      int bfn[maxn];
      queue<int> q;
      vector<int> e[maxn];
      vector<pii> quj[maxn];
      struct{
      	int opt,x,y;
      	int l1,r1,l2,r2;
      }wt[maxn];
      il void dfs1(int u,int fa){
      	dep[u]=dep[fa]+1;
      	anc[u][0]=fa;
      	for(int i=1;i<=20;i++){
      		anc[u][i]=anc[anc[u][i-1]][i-1];
      	}
      	for(int v:e[u]){
      		if(v==fa){
      			continue;
      		}
      		dfs1(v,u);
      	}
      }
      il int ganc(int u,int k){
      	int tmp=0;
      	while(k){
      		if(k&1){
      			u=anc[u][tmp];
      		}
      		k>>=1,tmp++;
      	}
      	return u;
      }
      il void bfs(){
      	int cnt=0;
      	q.push(1);
      	while(q.size()){
      		int u=q.front();
      		q.pop(),bfn[u]=++cnt;
      		for(int v:e[u]){
      			if(!bfn[v]){
      				q.push(v);
      			}
      		}
      	}
      }
      int rt[maxn],tot,ls[maxn*40],rs[maxn*40],sum[maxn*40],mn[maxn*40],mx[maxn*40];
      il int New(){
      	tot++;
      	ls[tot]=rs[tot]=sum[tot];
      	mn[tot]=inf,mx[tot]=-inf;
      	return tot;
      }
      il void pushup(int id){
      	sum[id]=sum[ls[id]]+sum[rs[id]];
      }
      il void build(int &id,int l,int r){
      	id=New();
      	if(l==r){
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(ls[id],l,mid);
      	build(rs[id],mid+1,r);
      }
      il void add(int &id,int l,int r,int p,int v){
      	if(!id){
      		id=New();
      	}
      	if(l==r){
      		mn[id]=min(mn[id],v);
      		mx[id]=max(mx[id],v);
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(p<=mid){
      		add(ls[id],l,mid,p,v);
      	}
      	else{
      		add(rs[id],mid+1,r,p,v);
      	}
      	mn[id]=min(mn[ls[id]],mn[rs[id]]);
      	mx[id]=max(mx[ls[id]],mx[rs[id]]);
      }
      il void upd(int &id,int fr,int l,int r,int p){
      	id=New();
      	if(l==r){
      		sum[id]=sum[fr]^1;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(p<=mid){
      		rs[id]=rs[fr];
      		upd(ls[id],ls[fr],l,mid,p);
      	}
      	else{
      		ls[id]=ls[fr];
      		upd(rs[id],rs[fr],mid+1,r,p);
      	}
      	pushup(id);
      }
      il int merge(int p,int q,int l,int r){
      	if(!p||!q){
      		return p+q;
      	}
      	if(l==r){
      		int x=New();
      		mn[x]=min(mn[p],mn[q]);
      		mx[x]=max(mx[p],mx[q]);
      		return x;
      	}
      	int mid=(l+r)>>1,x=New();
      	ls[x]=merge(ls[p],ls[q],l,mid);
      	rs[x]=merge(rs[p],rs[q],mid+1,r);
      	mn[x]=min(mn[ls[x]],mn[rs[x]]);
      	mx[x]=max(mx[ls[x]],mx[rs[x]]);
      	return x;
      }
      il int query(int id,int L,int R,int l,int r){
      	if(l>r||!id){
      		return 0;
      	}
      	if(L>=l&&R<=r){
      		return sum[id];
      	}
      	int mid=(L+R)>>1,res=0;
      	if(l<=mid){
      		res+=query(ls[id],L,mid,l,r);
      	}
      	if(r>mid){
      		res+=query(rs[id],mid+1,R,l,r);
      	}
      	return res;
      }
      il int qmn(int id,int l,int r,int p){
      	if(l==r){
      		return mn[id];
      	}
      	int mid=(l+r)>>1;
      	return p<=mid?qmn(ls[id],l,mid,p):qmn(rs[id],mid+1,r,p);
      }
      il int qmx(int id,int l,int r,int p){
      	if(l==r){
      		return mx[id];
      	}
      	int mid=(l+r)>>1;
      	return p<=mid?qmx(ls[id],l,mid,p):qmx(rs[id],mid+1,r,p);
      }
      il void dfs2(int u,int fa){
      	add(rt[u],1,n,dep[u],bfn[u]);
      	for(int v:e[u]){
      		if(v==fa){
      			continue;
      		}
      		dfs2(v,u);
      		rt[u]=merge(rt[u],rt[v],1,n);
      	}
      	for(pii v:quj[u]){
      		int k=v.fir,id=v.sec;
      		if(id>0){
      			wt[id].l1=qmn(rt[u],1,n,k);
      			wt[id].r1=qmx(rt[u],1,n,k);
      		}
      		else{
      			id=-id;
      			wt[id].l2=qmn(rt[u],1,n,k);
      			wt[id].r2=qmx(rt[u],1,n,k);
      		}
      	}
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1,u,v;i<n;i++){
      		cin>>u>>v;
      		e[u].pb(v),e[v].pb(u);
      	}
      	dfs1(1,0),bfs();
      	cin>>m;
      	for(int i=1,opt,x,y;i<=m;i++){
      		cin>>opt>>x;
      		wt[i].opt=opt,wt[i].x=x;
      		if(opt==2){
      			cin>>y;
      			wt[i].y=y;
      			if((y&1)||!y){
      				continue;
      			}
      			y>>=1;
      			if(y>=dep[x]){
      				continue;
      			}
      			x=ganc(wt[i].x,y);
      			quj[x].pb(mp(dep[wt[i].x],i));
      			x=ganc(wt[i].x,y-1);
      			quj[x].pb(mp(dep[wt[i].x],-i));
      		}
      	}
      	mn[0]=inf,mx[0]=-inf;
      	dfs2(1,0);
      	tot=0;
      	build(rt[0],1,n);
      	for(int i=1,opt,x,y;i<=m;i++){
      		opt=wt[i].opt,x=wt[i].x,y=wt[i].y;
      		switch(opt){
      			case 1:{
      				upd(rt[i],rt[i-1],1,n,bfn[x]);
      				break;
      			}
      			case 2:{
      				rt[i]=rt[i-1];
      				if(y&1){
      					cout<<"0\n";
      				}
      				else if(!y){
      					cout<<query(rt[i],1,n,bfn[x],bfn[x])<<"\n";
      				}
      				else{
      					y>>=1;
      					if(y>=dep[x]){
      						cout<<"0\n";
      					}
      					else{
      						cout<<query(rt[i],1,n,wt[i].l1,wt[i].l2-1)+query(rt[i],1,n,wt[i].r2+1,wt[i].r1)<<"\n";
      					}
      				}
      				break;
      			}
      			default:{
      				rt[i]=rt[x];
      				break;
      			}
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      H. Physical Education Lessons

      顏色段均攤 + 區(qū)間求和,使用珂朵莉樹,動態(tài)維護答案。時間復雜度 \(O(m\log m)\)。因為全是推平操作所以時間復雜度正確。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define lwrb lower_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      int n,m,ans;
      struct node{
      	int l,r,v;
      	node(int l=0,int r=0,int v=0):l(l),r(r),v(v){}
      	il bool operator<(const node &x)const{
      		return l<x.l;
      	}
      };
      set<node> odt;
      il void build(){
      	odt.insert(node(1,n+1,1));
      	ans=n;
      }
      il auto split(int x){
      	auto it=odt.lwrb(x);
      	if(it!=odt.end()&&it->l==x){
      		return it;
      	}
      	it--;
      	int l=it->l,r=it->r,v=it->v;
      	odt.erase(it);
      	odt.insert(node(l,x-1,v));
      	return odt.insert(node(x,r,v)).first;
      }
      il void assign(int l,int r,int v){
      	auto itr=split(r+1);
      	auto itl=split(l);
      	for(auto it=itl;it!=itr;it++){
      		ans-=it->v*(it->r-it->l+1);
      	}
      	odt.erase(itl,itr);
      	odt.insert(node(l,r,v));
      	ans+=v*(r-l+1);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	build();
      	while(m--){
      		int l,r,k;
      		cin>>l>>r>>k;
      		k--;
      		assign(l,r,k);
      		cout<<ans<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      I. Points

      將橫坐標離散化,對每個橫坐標開一個 set,維護這個橫坐標上的所有縱坐標,再開一個維護區(qū)間最大值的線段樹。修改直接在 set 和線段樹上修改即可。對于查詢,首先找到最小的滿足大于 \(x\) 且有縱坐標大于 \(y\) 的橫坐標 \(p\),再在 \(p\)setupper_bound 即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define lid id<<1
      #define rid id<<1|1
      #define lwrb lower_bound
      #define uprb upper_bound
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=2e5+5;
      int n,lsh[maxn],tot,zhi[maxn<<2];
      set<int> dv[maxn];
      struct{
      	int opt,x,y;
      }wt[maxn];
      il void pushup(int id){
      	zhi[id]=max(zhi[lid],zhi[rid]);
      }
      il void build(int id,int l,int r){
      	if(l==r){
      		dv[l].insert(-1);
      		zhi[id]=-1;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(lid,l,mid);
      	build(rid,mid+1,r);
      	pushup(id);
      }
      il void insert(int id,int l,int r,int x,int y){
      	if(l==r){
      		dv[x].insert(y);
      		zhi[id]=*dv[x].rbegin();
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(x<=mid){
      		insert(lid,l,mid,x,y);
      	}
      	else{
      		insert(rid,mid+1,r,x,y);
      	}
      	pushup(id);
      }
      il void erase(int id,int l,int r,int x,int y){
      	if(l==r){
      		dv[x].erase(y);
      		zhi[id]=*dv[x].rbegin();
      		return ;
      	}
      	int mid=(l+r)>>1;
      	if(x<=mid){
      		erase(lid,l,mid,x,y);
      	}
      	else{
      		erase(rid,mid+1,r,x,y);
      	}
      	pushup(id);
      }
      il int query(int id,int l,int r,int x,int y){
      	if(x>=r||zhi[id]<=y){
      		return -1;
      	}
      	if(l==r){
      		return l;
      	}
      	int mid=(l+r)>>1;
      	int res=query(lid,l,mid,x,y);
      	return ~res?res:query(rid,mid+1,r,x,y);
      }
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		string opt;
      		cin>>opt>>wt[i].x>>wt[i].y;
      //		cout<<opt<<"\n";
      		wt[i].opt=(opt[0]=='a'?1:(opt[0]=='r'?2:3));
      //		cout<<wt[i].opt<<" "<<wt[i].x<<" "<<wt[i].y<<"\n";
      		lsh[++tot]=wt[i].x;
      	}
      	sort(lsh+1,lsh+tot+1);
      	tot=unique(lsh+1,lsh+tot+1)-lsh-1;
      	build(1,1,tot);
      	for(int i=1,opt,x,y;i<=n;i++){
      //		cout<<i<<"\n";
      		opt=wt[i].opt,y=wt[i].y;
      		x=lwrb(lsh+1,lsh+tot+1,wt[i].x)-lsh;
      		switch(opt){
      			case 1:{
      				insert(1,1,tot,x,y);
      				break;
      			}
      			case 2:{
      				erase(1,1,tot,x,y);
      				break;
      			}
      			default:{
      				int p=query(1,1,tot,x,y);
      				if(~p){
      					cout<<lsh[p]<<" "<<*dv[p].uprb(y)<<"\n";
      				}
      				else{
      					cout<<"-1\n";
      				}
      				break;
      			}
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      J. Two Segments

      首先將枚舉原排列中的區(qū)間轉化為枚舉值域上的區(qū)間。
      從小往大對 \(r\) 掃描線,對于每個 \(l\in[1,r)\) 維護將 \([l,r]\) 在原排列中最少要分成多少段。顯然只有 \(1\)\(2\) 段才會產生貢獻。那么我們用線段樹維護值域上的每個 \(l\) 的最小段數(shù),并維護值域區(qū)間上的最小值與最小值和最小值加一的數(shù)量??紤]加入 \(p_i\),如何影響我們維護的值。首先對于 \(l\in[1,p_i]\),要多出一段。如果 \(p_{i-1}<p_i\),那么對于 \(l\in[1,p_{i-1}]\),會減少一段。\(p_{i+1}\) 同理。直接在線段樹上區(qū)間修改即可。時間復雜度 \(O(n\log n)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define lid id<<1
      #define rid id<<1|1
      using namespace std;
      namespace asbt{
      namespace cplx{bool begin;}
      const int maxn=3e5+5;
      int n,a[maxn],b[maxn],tag[maxn<<2];
      struct node{
      	int zhi,nm1,nm2;
      	node(int zhi=0,int nm1=0,int nm2=0):zhi(zhi),nm1(nm1),nm2(nm2){}
      	il node operator+(const node &x)const{
      		node res(min(zhi,x.zhi));
      		if(res.zhi==zhi){
      			res.nm1+=nm1;
      			res.nm2+=nm2;
      		}
      		else if(res.zhi+1==zhi){
      			res.nm2+=nm1;
      		}
      		if(res.zhi==x.zhi){
      			res.nm1+=x.nm1;
      			res.nm2+=x.nm2;
      		}
      		else if(res.zhi+1==x.zhi){
      			res.nm2+=x.nm1;
      		}
      		return res;
      	}
      }tr[maxn<<2];
      #define zhi(id) tr[id].zhi
      #define nm1(id) tr[id].nm1
      #define nm2(id) tr[id].nm2
      il void pushup(int id){
      	tr[id]=tr[lid]+tr[rid];
      }
      il void pushtag(int id,int v){
      	tag[id]+=v,zhi(id)+=v;
      }
      il void pushdown(int id){
      	if(tag[id]){
      		pushtag(lid,tag[id]);
      		pushtag(rid,tag[id]);
      		tag[id]=0;
      	}
      }
      il void build(int id,int l,int r){
      	if(l==r){
      		nm1(id)=1;
      		return ;
      	}
      	int mid=(l+r)>>1;
      	build(lid,l,mid);
      	build(rid,mid+1,r);
      	pushup(id);
      }
      il void add(int id,int L,int R,int l,int r,int v){
      	if(l>r){
      		return ;
      	}
      	if(L>=l&&R<=r){
      		pushtag(id,v);
      		return ;
      	}
      	pushdown(id);
      	int mid=(L+R)>>1;
      	if(l<=mid){
      		add(lid,L,mid,l,r,v);
      	}
      	if(r>mid){
      		add(rid,mid+1,R,l,r,v);
      	}
      	pushup(id);
      }
      il int query(int id,int L,int R,int l,int r){
      	if(l>r){
      		return 0;
      	}
      	if(L>=l&&R<=r){
      		int res=0;
      		if(zhi(id)<=2){
      			res+=nm1(id);
      		}
      		if(zhi(id)<=1){
      			res+=nm2(id);
      		}
      		return res;
      	}
      	pushdown(id);
      	int mid=(L+R)>>1,res=0;
      	if(l<=mid){
      		res+=query(lid,L,mid,l,r);
      	}
      	if(r>mid){
      		res+=query(rid,mid+1,R,l,r);
      	}
      	return res;
      }
      #undef zhi
      #undef nm1
      #undef nm2
      namespace cplx{
      	bool end;
      	il double usdmem(){return (&begin-&end)/1048576.0;}
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      		b[a[i]]=i;
      	}
      	ll ans=0;
      	build(1,1,n);
      	for(int i=1;i<=n;i++){
      		add(1,1,n,1,i,1);
      		if(a[b[i]-1]<i){
      			add(1,1,n,1,a[b[i]-1],-1);
      		}
      		if(a[b[i]+1]<i){
      			add(1,1,n,1,a[b[i]+1],-1);
      		}
      		ans+=query(1,1,n,1,i-1);
      	}
      	cout<<ans;
      	return 0;
      }
      }
      int main(){return asbt::main();}
      
      posted @ 2025-02-15 17:33  zhangxy__hp  閱讀(16)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲自拍偷拍福利小视频| 年轻女教师hd中字3| 成人午夜大片免费看爽爽爽| 色综合天天综合网中文伊| 九九九国产| 狠狠色丁香婷婷综合尤物| 色综合五月伊人六月丁香| 国产精品福利自产拍在线观看| 精品少妇av蜜臀av| 少妇宾馆粉嫩10p| 久热久热免费在线观视频| 亚洲av永久无码精品天堂久久| 日本少妇被黑人xxxxx| 91精品国产老熟女在线| 一区二区视频| 久久这里都是精品二| 国产中文字幕在线一区| 靖宇县| 亚洲男人电影天堂无码| 免费观看日本污污ww网站69| 最近免费中文字幕大全| 日韩三级一区二区在线看| 国产一区二三区日韩精品| 最新成免费人久久精品| 激情在线一区二区三区视频| 黄页网站在线观看免费视频 | 日本阿v片在线播放免费| 国产毛片子一区二区三区| 国产台湾黄色av一区二区| 国产精品一区二区三区激情| 成熟了的熟妇毛茸茸| 欧美大胆老熟妇乱子伦视频| 熟女性饥渴一区二区三区| 国产中文字幕一区二区| 中美日韩在线一区黄色大片| 黑人巨大精品oideo| 中文字幕久久精品波多野结| 亚洲精品国产男人的天堂| 亚洲 欧美 唯美 国产 伦 综合| 中文字幕有码无码人妻在线| 日本精品一区二区不卡|