zoukankan      html  css  js  c++  java
  • 【CF643G】Choosing Ads(线段树)

    点此看题面

    • 给定一个长度为(n)的序列和一个整数(p)
    • 要求支持两种操作,区间赋值;询问区间中出现次数至少占(p\%)的数,可以输出至多(lfloorfrac{100}p floor)个数,可以包含错解,但必须有正确的解。
    • (nle1.5 imes10^5,20le ple100)

    前置:一个经典的简单题

    一个很简单的问题,给定一个序列,求出其中出现超过一半的数。(要求不开数组)

    这时候我们就考虑,用这个数的出现次数减去其余所有数的出现次数是为正的。

    因此,我们可以把它看成一种格斗,确定一个数,血量就是它当前的出现次数。

    然后每加入一个数,如果和这个数一样就将血量加(1),如果不一样就将血量减(1)

    当血量减至(0)的时候这个数就死了,我们就需要把它换成一个新数。

    (说实话,这道题应该是我刚上(BZOJ)时做的第一道题,至今都给我留有很深的印象,这个套路我也一直都很想再度使用,今天终于有了机会。)

    扩展:区间的合并

    现在我们把上面这个问题扩展一下,想要用线段树来维护这个格斗过程,实现区间查询。

    然后我们发现,实际上完全可以让两个区间分别格斗出一个数来,如果这两个数相同就合并血量,否则保留血量大的并将它的血量减去小的血量。

    扩展:多个数的格斗

    回到这道题,相当于我们现在已经解决了(pge 51)时的部分。(区间赋值显然就把这个区间格斗出的数设为赋值的数,血量设为区间长度即可)

    而当(p)很小的时候,可能有多个数,其实不妨,只要把这(lfloorfrac {100}p floor)个数维护下来即可。

    具体地,就是用右区间格斗出的每个数去打左区间格斗出的每个数。

    如果有相同直接合并血量,如果左区间的数还未到(lfloorfrac{100}p floor)个直接加入。

    否则找到左区间中所有数和这个数中血量最少的那个,把其余数血量都减少它的血量,再把这个血量最少的数删去。

    尽管这样的合并是(lfloorfrac{100}p floor^2)的,但毕竟(lfloorfrac{100}p floorle5),随便过。

    代码:(O(nlognlfloorfrac{100}p floor^2))

    #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 150000
    #define K 5
    using namespace std;
    int n,p,a[N+5];struct Data
    {
    	int k,V[K],C[K];I Data() {k=0,memset(V,0,sizeof(V)),memset(C,0,sizeof(C));}
    	I friend Data operator + (Data x,Data y)//合并
    	{
    		for(RI i=0,j;i^y.k;++i)//枚举右区间每个数去打左区间
    		{
    			for(j=0;j^x.k&&x.V[j]^y.V[i];++j);if(j^x.k) {x.C[j]+=y.C[i];continue;}//如果存在相同直接合并血量
    			if(x.k^(100/p)) {x.V[x.k]=y.V[i],x.C[x.k++]=y.C[i];continue;}//如果左区间未满直接加入
    			for(j=0;j^x.k;++j) x.C[j]<y.C[i]&&(swap(x.V[j],y.V[i]),swap(x.C[j],y.C[i]),0);//找到血量最小的
    			for(j=0;j^x.k;++j) x.C[j]-=y.C[i];//把其他数的血量全减去该数血量
    		}return x;
    	}
    };
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);}
    	I void print(Con Data& v) {write(v.k),pc(' ');for(RI i=0;i^v.k;++i) write(v.V[i]),pc(' ');pc('
    ');}
    }using namespace FastIO;
    class SegmentTree
    {
    	private:
    		#define PT CI l=1,CI r=n,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU() (V[rt]=V[rt<<1]+V[rt<<1|1])
    		#define PD() (F[rt]&&(T(rt<<1,F[rt],mid-l+1),T(rt<<1|1,F[rt],r-mid),F[rt]=0))
    		#define T(x,v,c) (V[x].k=1,V[x].V[0]=F[x]=v,V[x].C[0]=c)//格斗出的数设为v,血量设为区间长度c
    		Data V[N<<2];int F[N<<2];
    	public:
    		I void B(PT) {if(l==r) return (void)T(rt,a[l],1);RI mid=l+r>>1;B(LT),B(RT),PU();}
    		I void U(CI L,CI R,CI v,PT)//区间赋值
    		{
    			if(L<=l&&r<=R) return (void)T(rt,v,r-l+1);RI mid=l+r>>1;PD();
    			L<=mid&&(U(L,R,v,LT),0),R>mid&&(U(L,R,v,RT),0),PU();
    		}
    		I Data Q(CI L,CI R,PT)//区间询问
    		{
    			if(L==l&&r==R) return V[rt];RI mid=l+r>>1;PD();if(R<=mid) return Q(L,R,LT);
    			if(L>mid) return Q(L,R,RT);return Q(L,mid,LT)+Q(mid+1,R,RT);
    		}
    }S;
    int main()
    {
    	RI Qt,i,op,x,y,v;for(read(n,Qt,p),i=1;i<=n;++i) read(a[i]);S.B();
    	W(Qt--) read(op,x,y),op==1?(read(v),S.U(x,y,v)):print(S.Q(x,y));return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)
    浙大数据结构课后习题 练习二 7-2 一元多项式的乘法与加法运算 (20 分)
    浙大数据结构课后习题 练习一 7-1 Maximum Subsequence Sum (25 分)
    浙大数据结构课后习题 练习一 7-1 最大子列和问题 (20 分)
    PAT Basic 1019 数字黑洞 (20 分)
    PAT Basic 1017 A除以B (20 分)
    PAT Basic 1013 数素数 (20 分)
    PAT Basic 1007 素数对猜想 (20 分)
    PAT Basic 1003 我要通过! (20 分)
    自动化运维——HelloWorld(一)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF643G.html
Copyright © 2011-2022 走看看