zoukankan      html  css  js  c++  java
  • bzoj 1901: Zju2112 Dynamic Rankings【整体二分+树状数组||主席树+树状数组】

    整体二分:
    对于每一个修改操作,标记为1,并且加一个标记为-1的这个位置原来值,并且对于a数列每个点都当成修改操作
    然后整体二分,扫当前操作区间lr,把在值域区间标记为1和-1的操作都在树状数组对应位置上加/减出来,然后询问操作根据k和询问答案大小决定放在哪部分传下去

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1000005;
    int n,m,a[N],tot,ans[N],con,t[N],p[N];
    char s[5];
    struct qwe
    {
    	int o,l,r,v,k;
    	qwe(int O=0,int L=0,int R=0,int V=0,int K=0)
    	{
    		o=O,l=L,r=R,v=V,k=K;
    	}
    }q[N],ql[N],qr[N];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void update(int x,int v)
    {
    	for(int i=x;i<=n;i+=(i&(-i)))
    		t[i]+=v;
    }
    int ques(int x)
    {
    	int r=0;
    	for(int i=x;i>=1;i-=(i&(-i)))
    		r+=t[i];
    	return r;
    }
    void wk(int ll,int rr,int l,int r)
    {//cerr<<ll<<" "<<rr<<"   "<<l<<" "<<r<<endl;
    	if(l>r)
    		return;
    	if(ll==rr)
    	{
    		for(int i=l;i<=r;i++)
    			if(q[i].o==0)
    				ans[q[i].v]=ll;
    		return;
    	}
    	int mid=(ll+rr)>>1;
    	for(int i=l;i<=r;i++)
    	{
    		if(q[i].o==0)
    			p[i]=ques(q[i].r)-ques(q[i].l-1);
    		else if(q[i].v<=mid)
    			update(q[i].l,q[i].o);
    	}
    	for(int i=l;i<=r;i++)
    		if(q[i].o&&q[i].v<=mid)
    			update(q[i].l,-q[i].o);
    	int tl=0,tr=0,tot=l;
    	for(int i=l;i<=r;i++)
    	{
    		if(q[i].o==0)
    		{
    			if(q[i].k<=p[i])
    				ql[++tl]=q[i];
    			else
    			{
    				q[i].k-=p[i];
    				qr[++tr]=q[i];
    			}
    		}
    		else
    		{
    			if(q[i].v<=mid)
    				ql[++tl]=q[i];
    			else
    				qr[++tr]=q[i];
    		}
    	}
    	for(int i=1;i<=tl;i++)
    		q[tot++]=ql[i];
    	for(int i=1;i<=tr;i++)
    		q[tot++]=qr[i];
    	wk(ll,mid,l,l+tl-1);
    	wk(mid+1,rr,l+tl,r);
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read(),q[++tot]=qwe(1,i,0,a[i],0);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%s",s+1);
    		if(s[1]=='Q')
    		{
    			int l=read(),r=read(),k=read();
    			q[++tot]=qwe(0,l,r,++con,k);
    		}
    		else
    		{
    			int p=read(),v=read();
    			q[++tot]=qwe(-1,p,0,a[p],0);
    			q[++tot]=qwe(1,p,0,v,0);
    			a[p]=v;
    		}
    	}
    	wk(0,1e9,1,tot);
    	for(int i=1;i<=con;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    

    主席树:
    主席树维护的是前缀和,然后单点修改就很麻烦
    考虑前缀和数组是怎么解决这个问题的,就是用树状数组,每次修改改log个位置即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int N=20005;
    int n,m,v[N],a[N],con,h[N],tot,rt[N],cnt,l[30],r[30],x,y;
    char c[5];
    map<int,int>mp;
    struct qwe
    {
    	bool f;
    	int x,y,k;
    }q[N];
    struct xianduanshu
    {
    	int ls,rs,sum;
    }t[2200001];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    // int zhao(int x)
    // {
        // int l=1,r=tot,mid;
        // while(l<=r)
        // {
             // int mid=(l+r)>>1;
             // if(h[mid]<x)
    			 // l=mid+1;
             // else
    			 // r=mid-1;
            // }
        // return l;
    // }
    int lb(int x)
    {
    	return x&(-x);
    }
    void update(int la,int l,int r,int &rt,int w,int x)
    {
        rt=++con;
        t[rt].sum=t[la].sum+x;
    	t[rt].ls=t[la].ls;
    	t[rt].rs=t[la].rs;
        if(l==r)
    		return;
        int mid=(l+r)>>1;
        if(w<=mid)
    		update(t[la].ls,l,mid,t[rt].ls,w,x);
        else
    		update(t[la].rs,mid+1,r,t[rt].rs,w,x);
    }
    int ques(int ll,int rr,int k)
    {
        if(ll==rr)
    		return ll;
        int sl=0,sr=0;
        for(int i=1;i<=x;i++)
    		sl+=t[t[l[i]].ls].sum;
        for(int i=1;i<=y;i++)
    		sr+=t[t[r[i]].ls].sum;
        int mid=(ll+rr)>>1;
        if(sr-sl>=k)
        {
            for(int i=1;i<=x;i++)
    			l[i]=t[l[i]].ls;
            for(int i=1;i<=y;i++)
    			r[i]=t[r[i]].ls;
            return ques(ll,mid,k);
        }
        else
        {
            for(int i=1;i<=x;i++)
    			l[i]=t[l[i]].rs;
            for(int i=1;i<=y;i++)
    			r[i]=t[r[i]].rs;
            return ques(mid+1,rr,k-(sr-sl));
        }
    }
    int main()
    {
    	n=read(),m=read();
    	con=n;
    	for(int i=1;i<=n;i++)
    		v[i]=read(),a[i]=v[i];
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%s",c);
    		q[i].x=read(),q[i].y=read();
    		if(c[0]=='Q')
    		{
    			q[i].f=1;
    			q[i].k=read();
    		}
    		else
    			a[++con]=q[i].y;
    	}
    	sort(a+1,a+1+con);
    	h[++tot]=a[1];
    	for(int i=2;i<=con;i++)
    	if(a[i]!=a[i-1])
    		h[++tot]=a[i],mp[a[i]]=tot;
    	for(int i=1;i<=n;i++)
    	{
    		int tmp=mp[v[i]];
    		for(int j=i;j<=n;j+=lb(j))
    			update(rt[j],1,tot,rt[j],tmp,1);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(q[i].f)
    		{
    			x=0,y=0;
    			q[i].x--;
    			for(int j=q[i].x;j>0;j-=lb(j))
    				l[++x]=rt[j];
    			for(int j=q[i].y;j>0;j-=lb(j))
    				r[++y]=rt[j];
    			printf("%d
    ",h[ques(1,tot,q[i].k)]);
    		}
    		else
    		{
    			int tmp=mp[v[q[i].x]];
    			for(int j=q[i].x;j<=n;j+=lb(j))
    				update(rt[j],1,tot,rt[j],tmp,-1);
    			v[q[i].x]=q[i].y;
    			tmp=mp[q[i].y];
    			for(int j=q[i].x;j<=n;j+=lb(j))
    				update(rt[j],1,tot,rt[j],tmp,1);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    开启gpu加速的高性能移动端相框组件!
    一看就懂得移动端rem布局、rem如何换算
    加密算法
    YDNKJS 笔记
    JavaScript函数
    测试下
    console前端代码自动删除QQ空间我的说说
    前端规范
    解决方案
    重读js高程笔记二
  • 原文地址:https://www.cnblogs.com/lokiii/p/10748711.html
Copyright © 2011-2022 走看看