CSU-ACM training - Templates - Chairman of the tree

原hdu 2665 Kth number

The meaning of problems

For \ (n-\) number and \ (m \) queries, each query interval comprising \ ([X, Y] \) , seeking the first interval \ (K \) a large number of

Thinking

Be persistent tree line, namely, the Chairman tree, first create an empty tree line, use \ (root \) index indicates the access time after the first few, discrete data. Note that index starts at 1.
Note that \ (CNT \) may be scrambled, but \ (the root \) control the time interval, i.e. the time represented by \ (I \) is the root node is \ (Nodes [the root [I]] \) , \ (Nodes \ ) a \ (L \) and \ (R & lt \) to control the relationship between the left and right of the tree.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct{
    int l,r,sum;
}NODE;NODE nodes[20*MAXN];
int root[MAXN],a[MAXN],b[MAXN];
int n,m,cnt,p;

int getid(int x)
{//离散化 
    return lower_bound(b+1,b+1+p,x)-b;
}
void build(int l,int r,int &cur)
{//建立空树 
    nodes[cur].sum=nodes[cur].l=nodes[cur].r=0;
    cur=++cnt;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,nodes[cur].l);
    build(mid+1,r,nodes[cur].r);
}
void update(int l,int r,int &cur,int pre,int pos)
{
    cur=++cnt;//表示新开的节点 
    nodes[cur].l=nodes[pre].l;
    nodes[cur].r=nodes[pre].r;
    nodes[cur].sum=nodes[pre].sum+1;//记录该点该时间之前有多少的数字 
    if(l==r)return ;
    int mid=(l+r)>>1;//每次按照pos的值插入到1~p的范围中 
    if(pos<=mid)update(l,mid,nodes[cur].l,nodes[pre].l,pos);
    else update(mid+1,r,nodes[cur].r,nodes[pre].r,pos);
}
int query(int l,int r,int x,int y,int key)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int sum=nodes[nodes[y].l].sum-nodes[nodes[x].l].sum;//时间区间内个数 
    if(key<=sum)//查找右区间 
        return query(l,mid,nodes[x].l,nodes[y].l,key);
    else//查找左区间 
        return query(mid+1,r,nodes[x].r,nodes[y].r,key-sum);
}
void start()
{
    int x,y,k;

    memset(root,0,sizeof(root));
    cnt=0;
    FOR2(i,1,n)
    {
        cin>>a[i];
        b[i]=a[i];
    }
    cnt=0;
    sort(b+1,b+n+1);//离散化 
    p=unique(b+1,b+n+1)-b-1;//数据范围 
    build(1,p,root[0]); //建立时间点为0 的空树 
    FOR2(i,1,n)//i表示时间 ,按时间插入a[i]元素到线段树 
        update(1,p,root[i],root[i-1],getid(a[i])); //按照a[i]在b[i]中的大小插入到不同位置 
    while(m--)
    {
        cin>>x>>y>>k;//k=y-x-k+2;第K大和第K小的差别 
        cout<<b[query(1,p,root[x-1],root[y],k)]<<endl;//区间第K大就是求 时间区间的第K大 
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
    memset(root,0,sizeof(root));
        cin>>n>>m;
        start();
    }
}

原hdu 4348 To the moon

The meaning of problems

Segment tree and interval may be persistent, typical problems board, C represents the addition segment, Q represents a query interval, H query value representing the interval of time t, B t represents the time of return, then can not move forward.

The basic idea

First, you need to learn basic lazy node labeled sections and tree line, and then change, specifically to see the code, it is to add a layer of root node time
the array must be open to around 25W, 20W or less will burst out of bounds wrong! Can not open too much (more than 28W, like I did with a spatial structure optimization), it will burst memory T_T .

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct {
    int l,r;
    ll w,laz;
}NODE; NODE nodes[2500010];
int n,m,root[MAXN],cnt,x,y,d,t,now,num;
ll ans;

int build(int l,int r)
{
    int cur;
    cur=num++;
    nodes[cur].l=nodes[cur].r=nodes[cur].w=nodes[cur].laz=0;
    if(l==r)
    {
        cin>>nodes[cur].w;
        return cur;
    }
    int mid=(l+r)>>1;
    nodes[cur].l=build(l,mid);
    nodes[cur].r=build(mid+1,r);
    nodes[cur].w=nodes[nodes[cur].l].w+nodes[nodes[cur].r].w;//递归建树 
    return cur;//返回节点坐标 
}

int update(int pre,int x,int y,int l,int r,int d)
{
    int cur=num++;
    nodes[cur]=nodes[pre];
    nodes[cur].w+=d*(min(y,r)-max(x,l)+1);
    if(x<=l&&r<=y)
    {
        nodes[cur].laz+=d;//懒节点,建议使用返回值的函数 
        return cur;
    }
    int mid=(l+r)/2;
    if(x<=mid)
    {//左区间查询 
        nodes[cur].l=update(nodes[cur].l,x,y,l,mid,d);
    }
    if(y>mid)
    {//右区间查询 
        nodes[cur].r=update(nodes[cur].r,x,y,mid+1,r,d);
    }
    return cur;//返回节点坐标 
}

ll query(int cur,int x,int y,int l,int r)
{
    ll res=nodes[cur].laz*(min(y,r)-max(x,l)+1);//懒节点不用下传,这是返回函数的好处,不返回值的函数需要每次修改节点的w和子节点的laz标志 
    if(x<=l&&r<=y)
    {
        return nodes[cur].w;
    }
    int mid=(l+r)/2;
    if(x<=mid)res+=query(nodes[cur].l,x,y,l,mid);
    if(y>mid)res+=query(nodes[cur].r,x,y,mid+1,r);
    return res;
}

int main()
{
    bool flag=false;
    while(cin>>n>>m)
    {
        if(flag)cout<<endl;
        else flag=true;
        memset(root,0,sizeof(root));
        memset(nodes,0,sizeof(nodes));
        num=now=0;
        root[now]=build(1,n);
        while(m--)
        {
            char op;cin>>op;
            while(op=='\n')cin>>op;
            if(op=='C')
            {
                cin>>x>>y>>d;
                now++;//线段树时间坐标 
                root[now]=update(root[now-1],x,y,1,n,d);
            }
            if(op=='Q')
            {
                cin>>x>>y;
                cout<<query(root[now],x,y,1,n)<<endl;
            }
            if(op=='H')
            { 
                cin>>x>>y>>t;
                cout<<query(root[t],x,y,1,n)<<endl;
            }
            if(op=='B')
            {
                cin>>now;
            }
        }
    }
    return 0;
}

原hdu 6278 Just h-index

The meaning of problems

Similar to hdu 2665, looking for the first interval \ (K \) small numbers \ (a_k \) , so as to satisfy \ (. 1-a_k <= \) {greater than \ (a_k-1 \) number}

The basic idea

K binary search of small, i.e. mid, query discrete number of K-1, so that the number of conditions are met. The key is dichotomous

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include<iomanip>
#define FOR(i,a,b) for(int i=a;i<b;i++)
#define FOR2(i,a,b) for(int i=a;i<=b;i++)
#define sync ios::sync_with_stdio(false);cin.tie(0) 
#define ll long long
#define MAXN 100010
using namespace std;
typedef struct{
    int l,r;
    ll w;
}NODE;NODE nodes[24*MAXN];
int root[24*MAXN],num,now,n,q,p;
ll arr[MAXN],b[MAXN];
int getid(ll x)
{
    return lower_bound(b,b+p,x)-b+1;
}
void build(int l,int r,int &cur)
{//建立空树 
    nodes[cur].l=nodes[cur].r=nodes[cur].w=0;
    num++;
    cur=num;
    if(l==r)return  ;
    int mid=(l+r)>>1;
    build(l,mid,nodes[cur].l);
    build(mid+1,r,nodes[cur].r);
}
void update(int l,int r,int &cur,int pre,int pos)
{
    num++;//建立新节点
    cur=num;
    nodes[cur].l=nodes[pre].l;
    nodes[cur].r=nodes[pre].r;
    nodes[cur].w=nodes[pre].w+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)update(l,mid,nodes[cur].l,nodes[pre].l,pos);
    else update(mid+1,r,nodes[cur].r,nodes[pre].r,pos);
}

int query(int l,int r,int x,int y,int key)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int c=nodes[nodes[y].l].w-nodes[nodes[x].l].w;//区间个数 
    if(key<=c)return query(l,mid,nodes[x].l,nodes[y].l,key);//左区间
    else return query(mid+1,r,nodes[x].r,nodes[y].r,key-c);//右区间 
}
void start()
{
    p=num=now=0;
    
    FOR(i,0,n)
    {
        cin>>arr[i];
        b[i]=arr[i];
    }
    
    sort(b,b+n);
    p=unique(b,b+n)-b;//离散化 
    
    build(1,p,root[0]);
    FOR(i,0,n)update(1,p,root[i+1],root[i],getid(arr[i]));
    
    while(q--)
    {
        int x,y;cin>>x>>y;
        int l=1,r=y-x+1,rr=r,ans=1;//l r表示查询的区间大小,确定mid 
        while(l<=r)
        {
            int mid=(l+r)>>1;
            int t=query(1,p,root[x-1],root[y],mid);//求区间第mid大的数 
//          cout<<"mid="<<mid<<"t="<<t<<"b="<<b[t-1]<<endl;
            if(b[t-1]>=rr-mid+1) {
                ans=rr-mid+1;
                r=mid-1; 
            }
            else l=mid+1;
        }
        cout<<ans<<endl;
    }
}
int main()
{
    while(cin>>n>>q)
    {
        start();
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/tldr/p/11246857.html