POJ2104 整体二分、树套树

题目大意:
给你一串数字,然后给你两种操作:
1:1 l v  
操作一:把下标为l的点的值替换为v
2:2 l r k  
操作二:在[l,r]区间求第k大值!

1.整体二分
对于初始数字,变为插入操作
按操作的时间顺序排列各个操作,对于修改操作拆为删除和加入操作:
1 删除之前插入的数字,2. 加入新的数字
接下来分治二分答案:
对于mid,如果插入或者删除的数字<=mid那么应该放到左区间,并且用树状数组(其他数据结构也行)
维护前X个位置有多少个数字在左边。
对于询问:如果l,r区间在左边的数字>=k那么答案在左边,否则答案在右边,并且更新K,k=k-这个区间去左边的数字个数
当low =high的时候,说明low就是答案了,只要更新询问还在low,low之间的答案即可。
复杂度分析:分治的深度是log(S)s是数据的范围。
每个询问每次被分到左边或者右边,会有log(s)次操作。每个插入或者删除也是。
但是要用树状数组维护多少个数字在左边,要log(n)次更新或者查询。

复杂度是n*log(s)*log(n)

#include  
#include  
#include  
#include  
#include  
using namespace std;  
#define maxn 300007  
int tree[maxn];  
void add(int p,int n){  
    for(;p0;p-=p&(-p))  
        ans += tree[p];  
    return ans;  
}  
  
struct Node{  
    int l,r,k,ty,ans;  
};  
Node p[maxn];  
int id1[maxn],id2[maxn];  
void CDQ(int L,int R,int low,int high){  
    if(R < L) return ;  
    if(low == high ){  
        for(;L<=R;L++){  
            p[id1[L]].ans = low;  
        }  
        return ;  
    }  
    int mid = (low+high)/2,l=L,r=R,k,u;  
    for(int i = L;i <= R; i++){  
        u = id1[i];  
       if(p[u].ty == 2){  
            k = query(p[u].r) - query(p[u].l-1);  
            if(k >= p[u].k) id2[l++] = u;  
            else {  
                p[u].k -= k;  
                id2[r--] = u;  
            }  
        }  
        else if(p[u].k <= mid){  
            add(p[u].l,p[u].ty);  
            id2[l++] = u;  
        }  
        else id2[r--] =  u;  
    }  
  
    for(int i = L; i <= R; i++){  
        u = id1[i];  
        if(p[u].ty != 2 && p[u].k <= mid) add(p[u].l,-p[u].ty);  
    }  
    for(k=L;k

2.树状数组套平衡树

我们将树状数组的每一个节点代表对应的数字(需要将询问读入,然后把所有出现的数字离散化),平衡树中保存每一个数在序列中的下标。
修改:将原来序列中的数字在对应的树状数组套的平衡树中删除,再同理插入新的数字
询问:考虑答案的二进制表示,通过巧妙地运用树状数组的性质,我们可以从高位往地位贪心的构造答案,每次贪心在平衡树中查找对应区间的数字个数。
修改时间复杂度O(log^2N)
询问时间复杂度O(log^2N)构造答案+树状数组单点查询+平衡树查询
#include   
#include   
#include   
#include   
#include   
#include   
#define MAXN 100002  
using namespace std;  
using namespace __gnu_pbds;  
struct query{int t,l,r,k;}q[MAXN];  
//保存询问   
tree,rb_tree_tag,tree_order_statistics_node_update>bit[MAXN*2];  
tree,rb_tree_tag,tree_order_statistics_node_update>::iterator it;  
//exSTL红黑树,G++ Only,低版本中null_type为null_mapped_type  
int num[MAXN],n,ql,qr,k,oper,lsh[MAXN*2],H,ct;  
//lsh为离散化数组 ,H为贪心构造答案的最高位   
int lowbit(int x){return x&(-x);}  
void add(int p,int num){  
    for(int i=p;i<=ct;i+=lowbit(i))  
        bit[i].insert(num);  
}  
//树状数组更新   
void del(int p,int num){  
    for(int i=p;i<=ct;i+=lowbit(i))  
        bit[i].erase(num);  
}  
//树状数组删除   
int pos(int num){return lower_bound(lsh,lsh+ct,num)-lsh+1;}  
// 返回离散化下标   
int query(int l,int r,int k){  
    int num=0;  
    for(int i=H;i;i>>=1){ //高位往地位贪心   
        int tmp=num+i;  
        if(tmp>ct)continue;  
        int kth=bit[tmp].order_of_key(r+1)-bit[tmp].order_of_key(l);  
        //平衡树查询   
        if(kth>=k)continue;  
        num=tmp,k-=kth;  
    }  
    return num;  
}  
//贪心构造答案   
int main(){  
    int t;  
    while(scanf("%d",&n)!=EOF){  
        ct=0;  
        for(int i=1;i<=n;i++){  
            scanf("%d",&num[i]);  
            lsh[ct++]=num[i];  
        }  
        scanf("%d",&t);  
        for(int i=0;i

3.线段树套treap

//#pragma warning (disable:4786)  
//#pragma comment(linker,"/STACK:102400000,102400000")  //手动扩栈  
//#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
#include   
using namespace std;  
const double eps = 1e-9;  
const double PI = acos(-1.00);  
//#define PI 3.1415926535897932384626433832795  
const double e = exp(1.0);  
#define INF 0x3f3f3f3f  
//#define INF 1e18  
//typedef long long LL;  
//typedef __int64 LL;  
#define ONLINE_JUDGE  
#ifndef ONLINE_JUDGE  
freopen("in.txt", "r", stdin);  
freopen("out.txt", "w", stdout);  
#endif  
  
  
#define N 600010  
#define M 100010  
struct treap  
{  
    int key,wht,count,sz,ch[2];  
} tp[N*15];  
int tree[N<<1];  
int nodecount,root;  
int IDX(int l,int r)  
{  
    return l+r | l!=r;  
}  
void init()  
{  
    tp[0].sz=0;  
    tp[0].wht=-INF;  
    nodecount=0;  
    root=0;  
}  
void update(int x)  
{  
    tp[x].sz=tp[tp[x].ch[0]].sz+tp[x].count+tp[tp[x].ch[1]].sz;  
}  
void rotate(int &x,int t)  
{  
    int y=tp[x].ch[t];  
    tp[x].ch[t]=tp[y].ch[!t];  
    tp[y].ch[!t]=x;  
    update(x);  
    update(y);  
    x=y;  
}  
void insert(int &x,int t)  
{  
    if(! x)  
    {  
        x=++nodecount;  
        tp[x].key=t;  
        tp[x].wht=rand();  
        tp[x].count=1;  
        tp[x].ch[0]=tp[x].ch[1]=0;  
    }  
    else if(tp[x].key==t)  tp[x].count++;  
    else  
    {  
        int k=tp[x].keyt) return select(tp[x].ch[0],t);  
    return tp[x].count+tp[tp[x].ch[0]].sz+select(tp[x].ch[1],t);  
}  
int a[N],b[N],ord[M][5],lb;  
int n,m,tt;  
int search(int x)  
{  
    int l=1,r=b[0],mid;  
    while (l<=r)  
    {  
        mid=(l+r)>>1;  
        if(b[mid]==x) return mid;  
        if(b[mid]>1;  
    if(i<=m) treeinsert(l,m,i,x);  
    else treeinsert(m+1,r,i,x);  
}  
void treedel(int l,int r,int i,int x)  
{  
    erase(tree[IDX(l,r)],x);  
    if(l==r) return;  
    int m=(l+r)>>1;  
    if(i<=m) treedel(l,m,i,x);  
    else treedel(m+1,r,i,x);  
}  
int query(int l,int r,int x,int y,int k)  
{  
    if(l==r) return l;  
    int m=(l+r)>>1;  
    int ans=select(tree[IDX(l,m)],y)-select(tree[IDX(l,m)],x);  
    if(ans>=k) return query(l,m,x,y,k);  
    return query(m+1,r,x,y,k-ans);  
}  
int main ()  
{  
    while (~scanf("%d",&n))  
    {  
        b[0]=1;  
        lb=0;  
        memset(tree,0,sizeof(tree));  
        init();  
        for(int i=1; i<=n; i++)  
        {  
            scanf("%d",&a[i]);  
            b[++lb]=a[i];  
        }  
        scanf("%d",&m);  
        for(int i=1; i<=m; i++)  
        {  
            int op;  
            int x,y,c;  
            scanf("%d",&op);  
            if(op == 2)  
            {  
                scanf("%d %d %d",&x,&y,&c);  
                ord[i][1]=1;  
                ord[i][2]=x;  
                ord[i][3]=y;  
                ord[i][4]=c;  
            }  
            else  
            {  
                scanf("%d %d",&x,&y);  
                ord[i][1]=2;  
                ord[i][2]=x;  
                ord[i][3]=y;  
                b[++lb]=y;  
            }  
        }  
        sort(b+1,b+1+lb);  
        for(int i=1; i<=lb; i++)  
            if(b[i]!=b[b[0]]) b[++b[0]]=b[i];  
        for(int i=1; i<=n; i++)  
        {  
            a[i]=search(a[i]);  
            treeinsert(1,b[0],a[i],i);  
        }  
        for(int i=1; i<=m; i++)  
        {  
            if(ord[i][1]==1)  
                printf("%d\n",b[query(1,b[0],ord[i][2]-1,ord[i][3],ord[i][4])]);  
            else  
            {  
                treedel(1,b[0],a[ord[i][2]],ord[i][2]);  
                a[ord[i][2]]=search(ord[i][3]);  
                treeinsert(1,b[0],a[ord[i][2]],ord[i][2]);  
            }  
        }  
    }  
    return 0;  
}  


你可能感兴趣的:(程序代码,算法分享,随手记事,POJ)