[ZOJ 2112] [lg2617] Dynamic Rankings

方法一,树套树

外层权值线段树记值域,内层平衡树记权值

修改就删掉原来的再加上新的

查询区间kth,就先二分值域,对于每个值域,查询一下下标在[l,r]区间内的数有多少个,然后跳就可以了

时间复杂度 (O(mlog^2 n)) 空间复杂度 (O(nlogn))

lg数据太毒瘤
...
拼命优化 本机3.3s,交上去一样T

可能treap会快一些?但是估计快不了1.3s,

qwq

Code:

/*
@Date    : 2019-07-08 18:33:36
@Author  : Adscn (adscn@qq.com)
@Link    : https://www.cnblogs.com/LLCSBlog
*/
#define FASTER
#ifdef FASTER
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#endif
#include<bits/stdc++.h>
using namespace std;
#define IL inline
#define RG register
#define gi io.xint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
IL int getint()
{
    RG int xi=0;
    RG char ch=gc;
    bool f=0;
    while(ch<'0'|ch>'9')ch=='-'?f=1:f,ch=gc;
    while(ch>='0'&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
    return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
    if(k<0)k=-k,putchar('-');
    if(k>=10)pi(k/10,0);
    putchar(k%10+'0');
    if(ch)putchar(ch);
}
IL unsigned int LOG2(unsigned int x)
{
    unsigned int ret;
    __asm__ __volatile__ ("bsrl %1, %%eax":"=a"(ret):"m"(x));
    return ret;
}
struct FastIO {
    static const int S = 1e7;
    int wpos;
    char wbuf[S];
    FastIO() : wpos(0) {}
    inline int xchar() {
        static char buf[S];
        static int len = 0, pos = 0;
        if (pos == len)
            pos = 0, len = fread(buf, 1, S, stdin);
        if (pos == len) exit(0);
        return buf[pos++];
    }
    inline int xuint() {
        int c = xchar(), x = 0;
        while (c <= 32) c = xchar();
        for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
        return x;
    }
    inline int xint()
    {
        int s = 1, c = xchar(), x = 0;
        while (c <= 32) c = xchar();
        if (c == '-') s = -1, c = xchar();
        for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
        return x * s;
    }
    inline void xstring(char *s)
    {
        int c = xchar();
        while (c <= 32) c = xchar();
        for (; c > 32; c = xchar()) * s++ = c;
        *s = 0;
    }
    inline void wchar(int x)
    {
        if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
        wbuf[wpos++] = x;
    }
    inline void wint(int x)
    {
        if (x < 0) wchar('-'), x = -x;
        char s[24];
        int n = 0;
        while (x || !n) s[n++] = '0' + x % 10, x /= 10;
        while (n--) wchar(s[n]);
        wchar('
');
    }
    inline void wstring(const char *s)
    {
        while (*s) wchar(*s++);
    }
    ~FastIO()
    {
        if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
    }
} io;
const int MAXN=1e5+7;
const int __SIZE_OF_MEM=4e6;
struct SplayTree{
    struct node;
    typedef node* tree;
    struct node{
        tree ch[2],par;
        int val,siz,cnt;
        node(){}
        node(int v,tree p){val=v,par=p;siz=cnt=1;ch[0]=ch[1]=NULL;}
    }*root;
    static node mem[__SIZE_OF_MEM],*stk[__SIZE_OF_MEM],**top;
    inline tree newnode(int v,tree p)
    {
        tree k=*--top;
        k->siz=k->cnt=1,k->ch[0]=k->ch[1]=NULL;
        k->val=v,k->par=p;
        return k;
    }
    inline void delnode(tree &x){*top++=x;x=0;}
    SplayTree(){clear();}
    inline int siz(tree x){return x?x->siz:0;}
    inline int ws(tree x,tree p){return p?p->ch[1]==x:0;}
    inline void connect(tree x,tree p,int wh){if(x)x->par=p;(p?p->ch[wh]:root)=x;}
    inline void pushup(tree x){if(x)x->siz=siz(x->ch[0])+siz(x->ch[1])+x->cnt;}
    inline void rotate(tree x)
    {
        tree p=x->par,g=p->par;
        bool t=ws(x,p);
        connect(x,g,ws(p,g));
        connect(x->ch[!t],p,t);
        connect(p,x,!t);
        pushup(p);
    }
    inline void Splay(tree x,tree y)
    {
        if(!x)return;
        while(x->par!=y)
        {
            tree p=x->par,g=p->par;
            if(g!=y)rotate(ws(x,p)^ws(p,g)?x:p);
            rotate(x);
        }
        pushup(x);
    }
public:
    inline void insert(int val)
    {
        if(!root){root=newnode(val,NULL);return;}
        #define nxt (val>=x->val)
        for(tree x=root;x;x=x->ch[nxt])
        {
            if(x->val==val)
            {
                ++x->cnt;
                Splay(x,NULL);
                return;
            }
            if(!x->ch[nxt])
            {
                x->ch[nxt]=newnode(val,x);
                Splay(x->ch[nxt],NULL);
                return;
            }
        }
        #undef nxt
    }
    inline void find(int val)
    {
        tree x=root;
        while(x&&x->ch[val>x->val]&&x->val!=val)x=x->ch[val>x->val];
        Splay(x,NULL);
    }
    inline int rank(int val)
    {
        insert(val);
        int ans=siz(root->ch[0])+root->cnt-1;
        del(val);
        return ans;
    }
    inline void del(int val)
    {
        if(empty())return;
        find(val);
        tree x=root;
        if(x->val!=val)return;
        if(x->cnt>1){--x->cnt,--x->siz;return;}
        if(!x->ch[0])
        {
            root=x->ch[1];
            if(root)root->par=NULL;
            delnode(x);
            return;
        }
        tree k=x->ch[0];
        while(k->ch[1])k=k->ch[1];
        Splay(k,x);
        root=k,k->par=NULL;
        connect(x->ch[1],k,1);
        pushup(k);
        delnode(x);
    }
    inline int num(int l,int r){/*cout<<l<<" "<<r<<endl;*/return rank(r)-rank(l-1);}
    inline void clear(){root=NULL;}
    inline bool empty(){return root==NULL;}
    inline void print(){_print(root);puts("");}
private:
    inline void _print(tree x)
    {
        if(!x)return;
        _print(x->ch[0]);
        printf("%d ",x->val);
        _print(x->ch[1]);
    }
};
SplayTree::node 
SplayTree::mem[__SIZE_OF_MEM],
*SplayTree::stk[__SIZE_OF_MEM],
**SplayTree::top=SplayTree::stk+__SIZE_OF_MEM;
const int MX=4e6;
struct node;
typedef node* tree;
struct node{
    SplayTree t;
    tree l,r;
    inline void insert(int k){t.insert(k);}
    inline void del(int k){t.del(k);}
    inline bool empty(){return t.empty();}
    inline int num(int l,int r){/*cout<<(int)t->root;*/return t.num(l,r);}
}*root,mem[MX],*stk[MX],**top=stk+MX;
inline tree newnode()
{
    tree p=*--top;
    p->l=p->r=0;
    p->t.clear();
    return p;
}
inline void insert(tree &rt,int x,int y,int L=0,int R=1e9)
{
    if(!rt)rt=newnode();
    rt->insert(y);
    if(L==R)return;
    int mid((L+R)>>1);
    if(x<=mid)insert(rt->l,x,y,L,mid);
    else insert(rt->r,x,y,mid+1,R);
}
inline void del(tree &rt,int x,int y,int L=0,int R=1e9)
{
    rt->del(y);
    if(L==R)return;
    int mid((L+R)>>1);
    if(x<=mid)del(rt->l,x,y,L,mid);
    else del(rt->r,x,y,mid+1,R);
}
inline int num(tree &rt,int k,int l_,int r_,int L=0,int R=1e9)
{
    if(L==R)return L;
    int lsiz=rt->l?rt->l->num(l_,r_):0;
    int mid((L+R)>>1);
    if(lsiz>=k)return num(rt->l,k,l_,r_,L,mid);
    return num(rt->r,k-lsiz,l_,r_,mid+1,R);
}
int a[MAXN];
signed main(void)
{
//	File("lg2617");
//	clock_t start,finish;
//	start=clock();
    for(SplayTree::node **bg=SplayTree::stk,*cp=SplayTree::mem,**ed=bg+__SIZE_OF_MEM;bg!=ed;)*(bg++)=cp++;
    for(node **bg=stk,*cp=mem,**ed=bg+MX;bg!=ed;)*(bg++)=cp++;
    int n=gi,m=gi;
    for(int i=1;i<=n;++i)a[i]=gi;
    for(int i=1;i<=n;++i)insert(root,a[i],i);
    while(m--)
    {
        char type=io.xchar();
        while(type!='Q'&&type!='C')type=io.xchar();
        int l,r,k;
        if(type=='Q')
        {
            l=gi,r=gi,k=gi;
            io.wint(num(root,k,l,r));
        }
        if(type=='C')
        {
            l=gi,k=gi;
            del(root,a[l],l);
            insert(root,a[l]=k,l);
        }
    }
//	finish=clock();
//	cerr<<(double)(finish-start)/CLOCKS_PER_SEC<<"s";
    return 0;
}

方法二

树状数组套动态开点值域线段树(主席树)

时间复杂度(O(mlog^{2}n))

空间复杂度(O(nlog^{2}n))

大概可以这么理解,树状数组跳lowbit的时候,一定可以保证你想访问的一个前缀被不重不漏地遍历到。

另外,我们发现,主席树做静态区间kth的时候,如果要更新,要更新n个线段树,时间复杂度无法接受。

但查询很快。

对于这种数据结构题,我们有个通用的套路,就是尽量让询问和修改的复杂度相等,这样整体的复杂度越低。

于是我们考虑树状数组下套一个线段树,代码也很简洁,如下

for(int i=pos;i<=n;i+=i&-i)modify(rt[i],val,v,1,tot);

这样想,假如线段树每次都全部修改,全部查询,那么和原来的c数组是等价的

那么我们现在换成高级的数据结构,每次查询前k个,那么我们还是能保证不重不漏的更新与查询。

就是这样

要离散化一下,因为有修改,所以就预先读入完,然后离散化后离线回答

如果强制在线,应该可以用平衡树来维护

Code:

/*
@Date    : 2019-07-08 18:33:36
@Author  : Adscn (adscn@qq.com)
@Link    : https://www.cnblogs.com/LLCSBlog
*/
//#define FASTER
#ifdef FASTER
#pragma GCC diagnostic error "-std=c++11"
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#endif
#include<bits/stdc++.h>
#include<unistd.h>
using namespace std;
#define IL inline
#define RG register
#define gi getint()
#define gc getchar()
#define File(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
IL int getint()
{
	RG int xi=0;
	RG char ch=gc;
	bool f=0;
	while(ch<'0'|ch>'9')ch=='-'?f=1:f,ch=gc;
	while(ch>='0'&ch<='9')xi=(xi<<1)+(xi<<3)+ch-48,ch=gc;
	return f?-xi:xi;
}
template<typename T>
IL void pi(T k,char ch=0)
{
	if(k<0)k=-k,putchar('-');
	if(k>=10)pi(k/10,0);
	putchar(k%10+'0');
	if(ch)putchar(ch);
}
IL unsigned int LOG2(unsigned int x)
{
	unsigned int ret;
	__asm__ __volatile__ ("bsrl %1, %%eax":"=a"(ret):"m"(x));
	return ret;
}
const int MAXN=1e5+7;
struct node{
	int v,l,r;
}t[MAXN*500];
int n,m;
int rt[MAXN],cnt;
int qx[MAXN],qy[MAXN],cntx,cnty;
struct oper{
	int type;
	int l,r,k;
	int pos,val;
}q[MAXN];
int tot;
int a[MAXN],b[MAXN*2];
void modify(int &now,int pos,int val,int l,int r)
{
	if(!now)now=++cnt;
	t[now].v+=val;
	if(l>=r)return;
	int mid=(l+r)>>1;
	//cerr<<l<<" "<<mid<<" "<<r<<endl;
	if(pos<=mid)modify(t[now].l,pos,val,l,mid);
	else modify(t[now].r,pos,val,mid+1,r);
}
inline void add(int pos,int v)
{
	int val=lower_bound(b+1,b+tot+1,a[pos])-b;
	for(int i=pos;i<=n;i+=i&-i)modify(rt[i],val,v,1,tot);
}
inline int query(int l,int r,int k,int sum=0)
{
	if(l==r)return l;
	int mid=(l+r)>>1;
	for(int i=1;i<=cntx;++i)sum-=t[t[qx[i]].l].v;
	for(int i=1;i<=cnty;++i)sum+=t[t[qy[i]].l].v;
	if(k<=sum)
	{
		for(int i=1;i<=cntx;++i)qx[i]=t[qx[i]].l;
		for(int i=1;i<=cnty;++i)qy[i]=t[qy[i]].l;
		return query(l,mid,k);
	}
	else 
	{
		for(int i=1;i<=cntx;++i)qx[i]=t[qx[i]].r;
		for(int i=1;i<=cnty;++i)qy[i]=t[qy[i]].r;
		return query(mid+1,r,k-sum);
	}
}
int main(int argc, char const *argv[])
{
	#ifndef ONLINE_JUDGE
	File("file");
	#endif
	n=gi,m=gi;
	for(int i=1;i<=n;++i)a[i]=gi,b[++tot]=a[i];
	for(int i=1;i<=m;++i)
	{
		char ch=getchar();
		while(ch!='Q'&&ch!='C')ch=getchar();
		if(ch=='Q')
		{
			q[i].type=1;
			q[i].l=gi,q[i].r=gi,q[i].k=gi;
		}
		if(ch=='C')
		{
			q[i].type=0;
			q[i].pos=gi,q[i].val=gi;
			b[++tot]=q[i].val;
		}
	}
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;++i)add(i,1);
	for(int i=1;i<=m;++i)
	{
		if(q[i].type)
		{
			cntx=cnty=0;
			for(int j=q[i].r;j;j-=j&-j)qy[++cnty]=rt[j];
			for(int j=q[i].l-1;j;j-=j&-j)qx[++cntx]=rt[j];
			pi(b[query(1,tot,q[i].k)],'
');
		}
		else add(q[i].pos,-1),a[q[i].pos]=q[i].val,add(q[i].pos,1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/LLCSBlog/p/11166881.html