zoukankan      html  css  js  c++  java
  • BZOJ 4399 魔法少女LJJ(线段树合并)

    题意

    https://www.lydsy.com/JudgeOnline/problem.php?id=4399

    思路

    码农题,需要一定代码功底。方法很暴力,先将权值离散,表示在线段树里储存的位置,每个连通块用一棵动点线段树存储,合并两个连通块直接对两个动点线段树进行合并,查询操作在当前连通块的线段树上进行,只不过有询问乘积大小,直接权值取原权值的 (ln​) ,比较和的大小即可。

    现在分析线段树合并的复杂度,举一个最基本的例子:权值为([1,n])(n) 棵动点线段树,每个线段树插入了一个权值,那么总共有 (nlog n) 个点,而每一次合并相当于少掉了一个点,那么合并完这 (n) 棵线段树后复杂度就是消失的点的个数,不会超过总共的点数,所以复杂度是 (n log n) 的。

    类似的,对最一般的情况,也是一样的分析方法,最后得出线段树合并的复杂度为节点个数的结论。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    typedef long long LL;
    using namespace std;
    const int N=4e5+5;
    const int NN=N*12;
    
    struct SegmentTree
    {
    	struct node
    	{
    		int cnt;double sum;
    		node operator +(const node &_)const
    		{
    			return (node){cnt+_.cnt,sum+_.sum};
    		}
    	};
    	node nd[NN];
    	int lson[NN],rson[NN],rt[N],tot;
    	int &operator [](const int x){return rt[x];}
    	void build()
    	{
    		memset(rt,0,sizeof(rt));
    		nd[tot=0]=(node){0,0};
    		lson[0]=rson[0]=0;
    	}
    	void create(int &k)
    	{
    		if(!k)k=++tot,nd[k]=nd[0],lson[k]=rson[k]=0;
    	}
    	void update(int &k,int x,int addcnt,double addsum,int l,int r)
    	{
    		create(k);
    		if(l==r)
    		{
    			nd[k].cnt+=addcnt;
    			nd[k].sum+=addsum;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(x<=mid)update(lson[k],x,addcnt,addsum,l,mid);
    		else update(rson[k],x,addcnt,addsum,mid+1,r);
    		nd[k]=nd[lson[k]]+nd[rson[k]];
    	}
    	int sweep_off(int &k,int L,int R,int l,int r)
    	{
    		if(!k)return 0;
    		if(L<=l&&r<=R){int res=nd[k].cnt;k=0;return res;}
    		int mid=(l+r)>>1,res=0;
    		if(L<=mid)res+=sweep_off(lson[k],L,R,l,mid);
    		if(R>mid)res+=sweep_off(rson[k],L,R,mid+1,r);
    		nd[k]=nd[lson[k]]+nd[rson[k]];
    		return res;
    	}
    	int querycnt(int k){return nd[k].cnt;}
    	double querysum(int k){return nd[k].sum;}
    	int queryKth(int k,int K,int l,int r)
    	{
    		if(l==r)return l;
    		int mid=(l+r)>>1;
    		if(nd[lson[k]].cnt>=K)return queryKth(lson[k],K,l,mid);
    		else return queryKth(rson[k],K-nd[lson[k]].cnt,mid+1,r);
    	}
    	void merge(int &x,int y,int l,int r)
    	{
    		if(!x||!y){x=(x|y);return;}
    		if(l==r){nd[x]=nd[x]+nd[y];return;}
    		int mid=(l+r)>>1;
    		merge(lson[x],lson[y],l,mid);
    		merge(rson[x],rson[y],mid+1,r);
    		nd[x]=nd[lson[x]]+nd[rson[x]];
    	}
    }ST;
    int n,m,fa[N];
    int op[N],a[N],b[N];
    int disc[N],tot;
    double logdisc[N];
    int getfa(int k){return k==fa[k]?k:fa[k]=getfa(fa[k]);}
    
    int main()
    {
    	scanf("%d",&m);
    	FOR(i,1,m)
    	{
    		scanf("%d%d",&op[i],&a[i]);
    		if(op[i]!=1&&op[i]!=7)scanf("%d",&b[i]);
    	}
    	
    	FOR(i,1,m)
    	{
    		if(op[i]==1)disc[++tot]=a[i];
    		else if(op[i]==3||op[i]==4)disc[++tot]=b[i];
    	}
    	sort(disc+1,disc+1+tot);
    	tot=unique(disc+1,disc+1+tot)-disc-1;
    	FOR(i,1,m)
    	{
    		if(op[i]==1)a[i]=lower_bound(disc+1,disc+1+tot,a[i])-disc;
    		else if(op[i]==3||op[i]==4)b[i]=lower_bound(disc+1,disc+1+tot,b[i])-disc;
    	}
    	FOR(i,1,tot)logdisc[i]=log(disc[i]);
    	
    	ST.build();
    	FOR(i,1,m)
    	{
    		if(op[i]==1)
    		{
    			n++;
    			fa[n]=n;
    			ST.update(ST[n],a[i],1,logdisc[a[i]],1,tot);
    		}
    		else if(op[i]==2)
    		{
    			a[i]=getfa(a[i]),b[i]=getfa(b[i]);
    			if(a[i]==b[i])continue;
    			ST.merge(ST[a[i]],ST[b[i]],1,tot);
    			fa[b[i]]=a[i];
    		}
    		else if(op[i]==3)
    		{
    			if(b[i]==1)continue;
    			a[i]=getfa(a[i]);
    			int cnt=ST.sweep_off(ST[a[i]],1,b[i]-1,1,tot);
    			ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot);
    		}
    		else if(op[i]==4)
    		{
    			if(b[i]==tot)continue;
    			a[i]=getfa(a[i]);
    			int cnt=ST.sweep_off(ST[a[i]],b[i]+1,tot,1,tot);
    			ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot);
    		}
    		else if(op[i]==5)
    		{
    			a[i]=getfa(a[i]);
    			printf("%d
    ",disc[ST.queryKth(ST[a[i]],b[i],1,tot)]);
    		}
    		else if(op[i]==6)
    		{
    			a[i]=getfa(a[i]),b[i]=getfa(b[i]);
    			if(ST.querysum(ST[a[i]])>ST.querysum(ST[b[i]]))
    				puts("1");
    			else puts("0");
    		}
    		else if(op[i]==7)
    		{
    			a[i]=getfa(a[i]);
    			printf("%d
    ",ST.querycnt(ST[a[i]]));
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    部署至Oracle数据库的注意事项
    当在centos上面部署项目时,mysql的一些驱动安装不上,
    drf利用redis做缓存是发生一点错误提示
    python字符串前面加个u代表什么
    在学习数据分析时,安装anaconda时遇到一点问题
    在使用scrapy框架爬取sina时,常见保存
    在linux上scrapyd部署scrapy项目时出现service_identity,并且不能识别其中的一个opentype模块
    如何在mysql增加一个和root权限一样的用户,安排
    mysq的root密码忘记,原来还有更优雅的解法
    mysql远程连接阿里云的Ubuntu服务器
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10159208.html
Copyright © 2011-2022 走看看