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

    点此看题面

    大致题意: 要求支持(7)种操作:新建一个权值为(x)的点;连接两个点;把(a)所在连通块小于(x)的点权修改为(x);把(a)所在连通块大于(x)的点权修改为(x);询问(a)所在连通块第(k)小的点权;询问(a)(b)所在连通块乘积的大小关系;询问(a)所在连通块点数。

    前言

    其实原题面里还有两个操作:断开一条边;删去一个点。

    一眼看上去似乎很不可做?

    然而,表示操作种类的(c)的范围是(cle7)。。。

    线段树合并

    考虑连接两个点其实就是合并两个连通块信息,然后又有询问(k)大值的操作,容易想到权值线段树合并。

    修改操作其实就是求出权值小于(大于)(x)的点数,将这一部分清零,并修改权值为(x)的点的数量。

    而比较乘积,一个套路的做法就是把所有数取个(log),这样乘法变加法,就可以维护并比较了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 400000
    #define LN 20
    #define DB double
    using namespace std;
    int n,f[N+5],Rt[N+5],dc,dv[N+5];struct Op {int op,x,y;}q[N+5];
    I int fa(CI x) {return f[x]?f[x]=fa(f[x]):x;}
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit (c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class SegmentTree
    {
    	private:
    		#define LT l,mid,O[rt].S[0]
    		#define RT mid+1,r,O[rt].S[1]
    		#define PU(x) (O[x].G=O[O[x].S[0]].G+O[O[x].S[1]].G,O[x].Sz=O[O[x].S[0]].Sz+O[O[x].S[1]].Sz)
    		#define PD(x) O[x].F&&(C(O[x].S[0]),C(O[x].S[1]),O[x].F=0)
    		#define C(x) (O[x].G=O[x].Sz=0,O[x].F=1)
    		int Nt;struct node {DB G;int Sz,F,S[2];}O[N*LN<<1];
    	public:
    		I DB operator [] (CI x) {return O[x].G;}
    		I void U(CI x,CI v,CI l,CI r,int& rt)//修改点权为x的点数为v
    		{
    			if(!rt&&(rt=++Nt),l==r) return (void)(O[rt].G=(O[rt].Sz=v)*log(dv[x]));PD(rt);
    			int mid=l+r>>1;x<=mid?U(x,v,LT):U(x,v,RT),PU(rt);
    		}
    		I void Merge(int& x,CI y)//线段树合并
    		{
    			if(!x||!y) return (void)(x|=y);PD(x),PD(y),O[++Nt]=O[x],O[x=Nt].G+=O[y].G,
    			O[x].Sz+=O[y].Sz,PD(x),PD(y),Merge(O[x].S[0],O[y].S[0]),Merge(O[x].S[1],O[y].S[1]);
    		}
    		I int Gsz(CI L,CI R,CI l,CI r,CI rt)//求点权在[L,R]范围内的点数
    		{
    			if(L<=l&&r<=R) return O[rt].Sz;int mid=l+r>>1;PD(rt);
    			return (L<=mid?Gsz(L,R,LT):0)+(R>mid?Gsz(L,R,RT):0);
    		}
    		I void Cl(CI L,CI R,CI l,CI r,CI rt)//清空[L,R]范围内的信息
    		{
    			if(L<=l&&r<=R) return (void)C(rt);int mid=l+r>>1;PD(rt),
    			L<=mid&&(Cl(L,R,LT),0),R>mid&&(Cl(L,R,RT),0),PU(rt);
    		}
    		I int GV(CI k,CI l,CI r,CI rt)//求k大值
    		{
    			if(l==r) return dv[l];int mid=l+r>>1;PD(rt);
    			return O[O[rt].S[0]].Sz>=k?GV(k,LT):GV(k-O[O[rt].S[0]].Sz,RT);
    		}
    }S;
    int main()
    {
    	RI Qt,i,x,y;for(F.read(Qt),i=1;i<=Qt;++i) F.read(q[i].op,q[i].x),q[i].op^7&&//读入并存储下询问
    		(q[i].op^1?F.read(q[i].y),(q[i].op==3||q[i].op==4)&&(dv[++dc]=q[i].y):dv[++dc]=q[i].x);
    	for(sort(dv+1,dv+dc+1),dc=unique(dv+1,dv+dc+1)-dv-1,i=1;i<=Qt;++i) switch(q[i].op)
    	{
    		case 1:S.U(lower_bound(dv+1,dv+dc+1,q[i].x)-dv,1,1,dc,Rt[++n]);break;//新建点,注意离散化
    		case 2:(x=fa(q[i].x))^(y=fa(q[i].y))&&(S.Merge(Rt[x],Rt[y]),f[y]=x);break;//不在同一连通块中就合并
    		case 3:q[i].y=lower_bound(dv+1,dv+dc+1,q[i].y)-dv,
    			x=S.Gsz(1,q[i].y,1,dc,Rt[q[i].x=fa(q[i].x)]),S.Cl(1,q[i].y,1,dc,Rt[q[i].x]),//求出点数,并清空
    			S.U(q[i].y,x,1,dc,Rt[q[i].x]);break;//修改
    		case 4:q[i].y=lower_bound(dv+1,dv+dc+1,q[i].y)-dv,
    			x=S.Gsz(q[i].y,dc,1,dc,Rt[q[i].x=fa(q[i].x)]),S.Cl(q[i].y,dc,1,dc,Rt[q[i].x]),//求出点数,并清空
    			S.U(q[i].y,x,1,dc,Rt[q[i].x]);break;//修改
    		case 5:F.writeln(S.GV(q[i].y,1,dc,Rt[fa(q[i].x)]));break;//询问k大值
    		case 6:F.writeln(S[Rt[fa(q[i].x)]]>S[Rt[fa(q[i].y)]]?1:0);break;//比较log大小
    		case 7:F.writeln(S.Gsz(1,dc,1,dc,Rt[fa(q[i].x)]));break;//询问连通块点数
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    springboot雷神更新
    JVM整理文档
    这是我见过BIO/NIO/AIO讲的最清楚的博客了
    redis主从机制
    mybatis是如何防止sql注入的
    分布式锁的实现方式简介
    Nginx简介
    .net 下的集合
    C#模拟百度登录
    WPF 将PPT,Word转成图片
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4399.html
Copyright © 2011-2022 走看看