[线段树合并][动态图]魔法少女LJJ

BZOJ4399
第3.4个操作直接上权值线段树
第1.2个操作线段树合并
第5个操作在权值线段树上二分
第7个操作并查集做
第8.9个操作可以用字符串模拟快速读入防止超时
第6个操作显然会炸,所以用对数比较, l o g ( m ∗ n ) = l o g ( m ) + l o g ( n ) log(m*n)=log(m)+log(n) log(mn)=log(m)+log(n)

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=400005,M=7000000;
int n,m,i,x,y,me[N][3],b[N],lim,f[N],tin[N],cnt;
int tot,l[M],r[M],sum[M];double cmp[M],lg[N];
int get(int x) {return f[x]==x?x:f[x]=get(f[x]);}
inline void pushup(int x){
	sum[x]=sum[l[x]]+sum[r[x]];
	cmp[x]=cmp[l[x]]+cmp[r[x]];
}
void ins(int &x,int a,int b,int c,int d,double e){
	if(!x) x=++tot;
	sum[x]+=d,cmp[x]+=e;
	if(a==b) return;
	int mid=(a+b)>>1;
	if(c<=mid) ins(l[x],a,mid,c,d,e);
	else ins(r[x],mid+1,b,c,d,e);
}
void re(int x,int a,int b,int c,int d){
	if(!sum[x])return;
	if(a==b){
		cnt+=sum[x],sum[x]=0,cmp[x]=0;
		return;
	}
	int mid=(a+b)>>1;
	if(c<=mid) re(l[x],a,mid,c,d);
	if(d>mid) re(r[x],mid+1,b,c,d);
	pushup(x);
}
int merge(int x,int y,int a,int b){
	if(!x)return y;
	if(!y)return x;
	if(a==b){
		sum[x]+=sum[y];
		cmp[x]+=cmp[y];
		return x;
	}
	int mid=(a+b)>>1;
	l[x]=merge(l[x],l[y],a,mid);
	r[x]=merge(r[x],r[y],mid+1,b);
	return pushup(x),x;
}
inline int kth(int x,int k){
	int a=1,b=lim,mid;
	while(a<b){
		mid=(a+b)>>1;
		if(sum[l[x]]>=k) b=mid,x=l[x];
		else k-=sum[l[x]],a=mid+1,x=r[x];
	}
	return a;
}
inline int find(int x){
	int l=1,r=lim,mid,t;
	while(l<=r){
		if(b[mid=(l+r)>>1]<=x) l=(t=mid)+1;
		else r=mid-1;
	}
	return t;
}
int main(){
	m=read();
	for(i=1;i<=m;i++){
		me[i][0]=read(),me[i][1]=read();
		if(me[i][0]>1&&me[i][0]<7) me[i][2]=read();
		if(me[i][0]==1) b[++lim]=me[i][1];
		if(me[i][0]==3||me[i][0]==4) b[++lim]=me[i][2];
	}
	sort(b+1,b+lim+1);
	for(i=1;i<=lim;i++) lg[i]=log(b[i]);
	for(i=1;i<=m;i++){
		x=me[i][1],y=me[i][2];
		if(me[i][0]==1){
			x=find(x),n++;
			f[n]=n,ins(tin[n],1,lim,x,1,lg[x]);
		}
		if(me[i][0]==2){
			x=get(x),y=get(y);
			if(x==y) continue;
			tin[f[x]=y]=merge(tin[x],tin[y],1,lim);
		}
		if(me[i][0]==3){
			x=get(x),y=find(y),cnt=0;
			if(y>1) re(tin[x],1,lim,1,y-1);
			if(cnt) ins(tin[x],1,lim,y,cnt,lg[y]*cnt);
		}
		if(me[i][0]==4){
			x=get(x),y=find(y),cnt=0;
			if(y<lim) re(tin[x],1,lim,y+1,lim);
			if(cnt) ins(tin[x],1,lim,y,cnt,lg[y]*cnt);
		}
		if(me[i][0]==5) printf("%d\n",b[kth(tin[get(x)],y)]);
		if(me[i][0]==6) puts(cmp[tin[get(x)]]>cmp[tin[get(y)]]?"1":"0");
		if(me[i][0]==7) printf("%d\n",sum[tin[get(x)]]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值