线段树整理

开始PHD生涯,好久不做题了,手生的不行,代码能力、算法能力直线下滑。

不管以后我做什么方向,做做题目能很好地锻炼我的思维,所以以后开始继续做题,纯粹为了玩!

先整理一下线段树方面的题目吧,最近项目有用到,还有一些新的线段树的题目陆续添加吧


1、单点更新,区间查询

/*
HDU1166
单点更新,对区间进行询问。
不必设置延迟标记,单点更新到叶子节点,正常进行区间查询
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
struct Seg_Tree_Node
{
    int left, right;
    int sum;
    int mid()
    {
        return (left + right) / 2;
    }
}tree[50000 * 3 + 12345];
int num[50000 + 123];
void update_info(int idx)
{
    tree[idx].sum = tree[LL(idx)].sum + tree[RR(idx)].sum;
}
void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    if(l == r)
    {
        tree[idx].sum = num[l];
        return;
    }
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
    update_info(idx);
}
void update(int x, int idx, int c)
{
    if(tree[idx].left == tree[idx].right)
    {
        tree[idx].sum += c;
        return;
    }
    int mid = tree[idx].mid();
    if(x <= mid) update(x, LL(idx), c);
    else update(x, RR(idx), c);
    update_info(idx);
}
int query(int l, int r, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        //printf("%d -> %d\n", tree[idx].left, tree[idx].right);
        return tree[idx].sum;
    }
    int mid = tree[idx].mid();
    if(r <= mid) return query(l, r, LL(idx));
    else if(l > mid)  return query(l, r, RR(idx));
    else return query(l, r, LL(idx)) + query(l, r, RR(idx));
}
int main()
{
    int T;
    int cas = 1;
    scanf("%d", &T);
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)  scanf("%d", &num[i]);
        build(1, n, 1);

        printf("Case %d:\n", cas++);
        char s[10];
        int x, y;
        while(1)
        {
            scanf("%s", s);
            if(strcmp(s, "End") == 0) break;
            else if(strcmp(s, "Query") == 0)
            {
                scanf("%d%d", &x, &y);
                if(x > y)
                {
                    int temp = x;
                    x = y;
                    y = temp;
                }
                printf("%d\n", query(x, y, 1));
            }
            else if(strcmp(s, "Sub") == 0)
            {
                scanf("%d%d", &x, &y);
                update(x, 1, -y);
            }
            else if(strcmp(s, "Add") == 0)
            {
                scanf("%d%d", &x, &y);
                update(x, 1, y);
            }
        }
    }
    return 0;
}

/*
HDU1754
单点更新,区间查询
*/

#include<iostream>
#define LL(x)  (x<<1)
#define RR(x) (x<<1|1)
using namespace std;
 
struct Seg_Tree
{
    int left,right,num;
    int calmid() { return (right+left)/2;}
}tree[600020];
int num[200010];
 
int build(int left,int right,int idx)
{
    tree[idx].left=left;
    tree[idx].right=right;
    if(left==right)
    {
        return tree[idx].num=num[left];
    }
    int mid=tree[idx].calmid();
    return tree[idx].num=max(build(left,mid,LL(idx)),build(mid+1,right,RR(idx)));
}
 
void update(int id,int x,int idx)
{
    if(tree[idx].left==tree[idx].right)
    {
        tree[idx].num=x;
        return ;
    }
    int mid=tree[idx].calmid();
    if(id<=mid)  update(id,x,LL(idx));
    else update(id,x,RR(idx));
    tree[idx].num=max(tree[LL(idx)].num,tree[RR(idx)].num);
}
 
int query(int left,int right,int idx)
{
    if(left<=tree[idx].left && right>=tree[idx].right) return tree[idx].num;
    int mid=tree[idx].calmid();
    if(right<=mid)  return query(left,right,LL(idx));
    else if(left>mid)  return query(left,right,RR(idx));
    else return max(query(left,mid,LL(idx)),query(mid+1,right,RR(idx)));
}
 
int main()
{
    int n,m,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
           scanf("%d",&num[i]);
        build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            char str[10];
            scanf("%s%d%d",&str,&a,&b);
            if(str[0]=='Q')   printf("%d/n",query(a,b,1));
            else update(a,b,1);
        }
    }
    return 0;
}



2、区间更新,区间查询

/*
HDU 1698
区间更新
*/

#include<stdio.h>
#define LL(x)  (x<<1)
#define RR(x)  (x<<1|1)
struct Seg_Tree
{
    int left,right,num;
    int calmid() {
        return (left+right)/2;
    }
} tree[300005];
void build(int left,int right,int idx)
{
    tree[idx].left=left;
    tree[idx].right=right;
    tree[idx].num=1;
    if(left==right)  return ;
    int mid=tree[idx].calmid();
    if(left<=mid) build(left,mid,LL(idx));
    if(right>mid) build(mid+1,right,RR(idx));
}
void update(int left,int right,int x,int idx)
{
    if(left<=tree[idx].left && right>=tree[idx].right)
    {
        tree[idx].num=x;
        return;
    }
    if(tree[idx].num!=-1)
    {
        tree[RR(idx)].num=tree[LL(idx)].num=tree[idx].num;
        tree[idx].num=-1;
    }
    int mid=tree[idx].calmid();
    if(left<=mid) update(left,right,x,LL(idx));
    if(right>mid) update(left,right,x,RR(idx));
}
int query(int left,int right ,int idx)
{
    if(left<=tree[idx].left && right>=tree[idx].right)
    {
        if(tree[idx].num!=-1)
            return tree[idx].num*(tree[idx].right-tree[idx].left+1);
    }
    int mid=tree[idx].calmid();
    if(right<=mid) return query(left,mid,LL(idx));
    else if(left>mid)  return query(mid+1,right,RR(idx));
    else
        return query(left,mid,LL(idx))+query(mid+1,right,RR(idx));
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d",&n);
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            update(a,b,c,1);
        }
        printf("Case %d: The total value of the hook is %d./n",cas++,query(1,n,1));
    }
    return 0;
}

/*
POJ3468
成段更新,总区间求和
*/
#include<stdio.h>
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
struct Seg_tree
{
    int left,right;
    __int64  sum,add;//用于标记下传,否则必TLE
    int clamid() {  return (left+right)/2; }
}tree[100001*3];
int num[100001];
int n,q;
void build(int l,int r,int idx)
{
    tree[idx].left=l;
    tree[idx].right=r;
    tree[idx].add=0;
    if(l==r)
    {
        tree[idx].sum=num[l];
        return ;
    }
    int mid=tree[idx].clamid();
    build(l,mid,LL(idx));
    build(mid+1,r,RR(idx));
    tree[idx].sum=tree[LL(idx)].sum+tree[RR(idx)].sum;
}
void Update(int l,int r,int idx,int c)
{
    if(l<=tree[idx].left&&r>=tree[idx].right)
    {
        tree[idx].add+=c;
        tree[idx].sum+=c*(tree[idx].right-tree[idx].left+1);
        return ;
    }
    if(tree[idx].add)
    {
        tree[LL(idx)].add+=tree[idx].add;
        tree[LL(idx)].sum+=tree[idx].add*(tree[LL(idx)].right-tree[LL(idx)].left+1);
        tree[RR(idx)].add+=tree[idx].add;
        tree[RR(idx)].sum+=tree[idx].add*(tree[RR(idx)].right-tree[RR(idx)].left+1);
        tree[idx].add=0;
    }
    int mid=tree[idx].clamid();
    if(r>mid) Update(l,r,RR(idx),c);
    if(l<=mid) Update(l,r,LL(idx),c);
    /*if(r>mid) Update(mid+1,r,RR(idx),c);
    if(l<=mid) Update(l,mid,LL(idx),c);这是错误的*/
    tree[idx].sum=tree[LL(idx)].sum+tree[RR(idx)].sum;
}
__int64  query(int l,int r,int idx)
{
    if(l<=tree[idx].left&&r>=tree[idx].right)
                 return tree[idx].sum;
    if(tree[idx].add)
    {
        tree[LL(idx)].add+=tree[idx].add;
        tree[LL(idx)].sum+=tree[idx].add*(tree[LL(idx)].right-tree[LL(idx)].left+1);
        tree[RR(idx)].add+=tree[idx].add;
        tree[RR(idx)].sum+=tree[idx].add*(tree[RR(idx)].right-tree[RR(idx)].left+1);
        tree[idx].add=0;
    }
    int mid=tree[idx].clamid();
    if(r<=mid) return query(l,r,LL(idx));
    else
    if(l>mid) return query(l,r,RR(idx));
    else
    return query(l,mid,LL(idx))+query(mid+1,r,RR(idx));
}
 
int main()
{
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        for(int i=1;i<=n;i++)  scanf("%d",&num[i]);
        build(1,n,1);
        for(int i=1;i<=q;i++)
        {
            char str[10];
            int a,b,c;
            scanf("%s",str);
            if(str[0]=='Q')
            {
                scanf("%d%d",&a,&b);
                printf("%I64d/n",query(a,b,1));
            }
            else
            {
                scanf("%d%d%d",&a,&b,&c);
                Update(a,b,1,c);
            }
        }
    }
    return 0;
}


/*
POJ2777
很裸的区间更新,区间查询
设置一个延迟标记,尽可能减少访问子节点次数
因为最多只有30种颜色,所以使用int类型进行位压缩
*/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
struct Seg_Tree_Node
{
    int left, right;
    int color;
    bool delay;
    int mid()
    {
        return (left + right) / 2;
    }
}tree[100000 * 3 + 1234];
int cnum;
void update_info(int idx)
{
    tree[idx].color = tree[LL(idx)].color | tree[RR(idx)].color;
}
void pushDown(int idx)
{
    tree[LL(idx)].color = tree[idx].color;
    tree[LL(idx)].delay = 1;
    tree[RR(idx)].color = tree[idx].color;
    tree[RR(idx)].delay = 1;
    tree[idx].delay = 0;
    tree[idx].color = 0;
}
void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    tree[idx].color = 1;
    tree[idx].delay = 0;
    if(l == r) return;
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
    update_info(idx);
}
void update(int l, int r, int idx, int c)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        tree[idx].color = 1 << (c - 1);
        tree[idx].delay = 1;//打上延迟标记
        return;
    }
    if(tree[idx].delay)  pushDown(idx);
    int mid = tree[idx].mid();
    if(r > mid) update(l, r, RR(idx), c);
    if(l <= mid) update(l, r, LL(idx), c);
    update_info(idx);
}
void query(int l, int r, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        cnum = cnum | tree[idx].color;
        return;
    }
    if(tree[idx].delay) pushDown(idx);
    int mid = tree[idx].mid();
    if(r > mid) query(l, r, RR(idx));
    if(l <= mid) query(l, r, LL(idx));
    update_info(idx);
}
int cal(int num)
{
    int sum = 0;
    while(num != 0)
    {
        if(num & 1)   sum++;
        num = num >> 1;
    }
    return sum;
}
int main()
{
    int l, t, o;
    while(scanf("%d%d%d", &l, &t, &o) != EOF)
    {
        build(1, l, 1);
        char s[10];
        int l, r, c;
        for(int i = 0; i < o; i++)
        {
            scanf("%s", s);
            if(s[0] == 'P')
            {
                scanf("%d%d", &l, &r);
                if(l > r)
                {
                    int temp = l;
                    l = r;
                    r = temp;
                }
                cnum = 0;
                query(l, r, 1);
                printf("%d\n", cal(cnum));
            }
            else
            {
                scanf("%d%d%d", &l, &r, &c);
                if(l > r)
                {
                    int temp = l;
                    l = r;
                    r = temp;
                }
                update(l, r, 1, c);
            }
        }
    }
    return 0;
}


/*
JOJ2445
区间更新,区间查询
这题的不同之处在于建树略微有点特别。
先用静态链表建好原始二叉树,接着DFS一遍找出每个父亲节点的管辖范围,类似于后序遍历
另外,这个题目左右子树互换不影响结果
*/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
const int MAXN = 20000 + 1234;
struct EDGE
{
    int u, v, next;
}edge[MAXN * 2];
struct Seg_Tree_Node
{
    int left, right;
    int sum;
    bool delay;
    int mid()
    {
        return (left + right) / 2;
    }
}tree[MAXN * 3];
int head[MAXN];
int cnt;
int vnum;
bool vis[MAXN];
int lid[MAXN], rid[MAXN];
void addedge(int a, int b)
{
    edge[cnt].u = a;
    edge[cnt].v = b;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}
int dfs(int u)
{
    int lmin = MAXN;
    vis[u] = 1;//�Ѿ��߹���
    for(int p = head[u]; p != -1; p = edge[p].next)
    {
        if(vis[edge[p].v])  continue;
        int t = dfs(edge[p].v);
        if(t < lmin) lmin = t;
    }
    rid[u] = ++vnum;
    if(lmin == MAXN)  lmin = rid[u];
    lid[u] = lmin;
    return lmin;
}
void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    tree[idx].delay = 0;
    tree[idx].sum = 0;
    if(l == r)  return;
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
}
void pushDown(int idx)
{
    int l = LL(idx), r = RR(idx);
    tree[l].sum = (tree[l].right - tree[l].left + 1) - tree[l].sum;
    tree[l].delay = 1 - tree[l].delay;
    tree[r].sum = (tree[r].right - tree[r].left + 1) - tree[r].sum;
    tree[r].delay = 1 - tree[r].delay;
    tree[idx].delay = 0;
}
void update_info(int idx)
{
    int l = LL(idx), r = RR(idx);
    tree[idx].sum = tree[l].sum + tree[r].sum;
}
void update(int l, int r, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        tree[idx].sum = (tree[idx].right - tree[idx].left + 1) - tree[idx].sum;
        tree[idx].delay = 1 - tree[idx].delay;
        return;
    }
    if(tree[idx].delay) pushDown(idx);
    int mid = tree[idx].mid();
    if(r > mid) update(l, r, RR(idx));
    if(l <= mid) update(l, r, LL(idx));
    update_info(idx);
}
int query(int l, int r, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        return tree[idx].sum;
    }
    if(tree[idx].delay) pushDown(idx);
    int mid = tree[idx].mid();
    if(r <= mid) return query(l, r, LL(idx));
    else if(l > mid) return query(l, r, RR(idx));
    else return query(l, r, LL(idx)) + query(l, r, RR(idx));
    update_info(idx);
}
int main()
{
    int n, m;
    while(scanf("%d", &n) != EOF)
    {
        cnt = 0;
        vnum = 0;
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        int a, b;
        for(int i = 1; i < n; i++)
        {
            scanf("%d%d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }

        dfs(1);
        //for(int i = 1; i <= n; i++)  printf("%d: %d %d\n", i, lid[i], rid[i]);

        build(1, n, 1);
        scanf("%d", &m);

        char str[10];
        int x;
        for(int i = 0; i < m; i++)
        {
            scanf("%s", str);
            if(str[0] == 'Q')
            {
                scanf("%d", &x);
                printf("%d\n", query(lid[x],rid[x], 1));
            }
            else
            {
                scanf("%d", &x);
                update(lid[x], rid[x], 1);
            }
        }
    }
    return 0;
}

/*
树状数组+二分同样可做
当然这题目数据量小,暴力都能过

纯粹套一下线段树的做法
属于单点更新和区间查询
线段树记录每段线段的和,访问略微有点特殊
访问可以看作是,问当和为x的时候,是第几个数
接着更新和访问一起就可以了
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
const int MAXN = 10000;
int rid[MAXN];
int num[MAXN];
struct Seg_Tree_Node
{
    int left, right;
    int sum;
    int mid()
    {
        return (left + right) / 2;
    }
}tree[MAXN * 3];
void update_info(int idx)
{
    tree[idx].sum = tree[LL(idx)].sum + tree[RR(idx)].sum;
}
void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    if(l == r)
    {
        tree[idx].sum = 1;
        return;
    }
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
    update_info(idx);
}
//查询和修改统一
int query(int c, int idx)
{
    int ans;
    if(tree[idx].left == tree[idx].right)
    {
        tree[idx].sum = 0;
        return tree[idx].left;
    }
    int mid = tree[idx].mid();
    if(tree[LL(idx)].sum >= c) ans = query(c, LL(idx));
    else ans = query(c - tree[LL(idx)].sum, RR(idx));
    update_info(idx);
    return ans;
}
int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 2; i <= n; i++) scanf("%d", &rid[i]);
        build(1, n, 1);
        for(int i = n; i >= 2; i--)
        {
            num[i] = query(rid[i] + 1, 1);
        }
        num[1] =query(1, 1);
        for(int i = 1; i <= n; i++)  printf("%d\n", num[i]);
    }
    return 0;
}


/*POJ 2528这题目需要离散化,离散化的时候注意一下,相连的数离散化后相差为1,
否则相差为2更新时候使用延迟标记最后询问的时候一次到底*/
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define LL(x)  (x<<1)
#define RR(x)  (x<<1|1)
using namespace std;
struct  T
{
    int num,id,flag,t;
} s[20010];
struct Seg_Tree
{
    int left,right,col;
    int mid() { return (left+right)/2;}
}tree[30010*2*3];
int x[10010],y[10010],ans;
bool flag[20010*3];
bool cmp(T a, T b)
{
    return a.num<b.num;
}
void build(int l,int r,int idx)
{
    tree[idx].left=l;
    tree[idx].right=r;
    tree[idx].col=-1;
    if(l==r)   return ;
    int mid=tree[idx].mid();
    build(l,mid,LL(idx));
    build(mid+1,r,RR(idx));
}
void update(int l,int r,int c,int idx)
{
    if(l<=tree[idx].left&&r>=tree[idx].right)
    {
        tree[idx].col=c;
        return;
    }
    if(tree[idx].col!=-1)
    {
        tree[LL(idx)].col=tree[RR(idx)].col=tree[idx].col;
        tree[idx].col=-1;
    }
    int mid=tree[idx].mid();
    if(l<=mid)  update(l,r,c,LL(idx));
    if(r>mid)  update(l,r,c,RR(idx));
}
void query(int l,int r,int idx)
{
    if(tree[idx].col!=-1)
    {
        if(!flag[tree[idx].col])
        {
            ans++;
            flag[tree[idx].col]=true;
        }
        return;//important
    }
    int mid=tree[idx].mid();
    if(l<=mid)  query(l,r,LL(idx));
    if(r>mid)  query(l,r,RR(idx));
}
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        memset(flag,false,sizeof(flag));
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            s[2*i].id=i;
            s[2*i].num=x[i];
            s[2*i].flag=0;
            s[2*i+1].id=i;
            s[2*i+1].num=y[i];
            s[2*i+1].flag=1;
        }
        sort(s,s+2*n,cmp);
        s[0].t=0;
        for(int i=1; i<2*n; i++)
            if(s[i].num!=s[i-1].num)
            {
                if(s[i].num-1>s[i-1].num)  s[i].t=s[i-1].t+2;
                        else  s[i].t=s[i-1].t+1;
            }
            else
                s[i].t=s[i-1].t;
        for(int i=0; i<2*n; i++)
            if(s[i].flag==0) x[s[i].id]=s[i].t;
                        else y[s[i].id]=s[i].t;
        build(0,s[2*n-1].t,1);
        for(int i=0; i<n; i++)  update(x[i],y[i],i,1);
        ans=0;
        query(0,s[2*n-1].t,1);
        printf("%d\n",ans);
    }
    return 0;
}

/*
POJ 3667 Hotel
当年的第一道用线段树做区间合并的题目
delay做延迟标记
lval表示左边的最长连续区间
rval表示右边的最长连续区间
lval表示这个线段的最长连续区间
接着维护上面几个变量即可
因为每次查询后都要更新,所以这个query函数里可以暂时不加更新
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
const int MAXN = 50000 + 1234;
struct Seg_Tree_Node
{
    int left, right;
    int delay;
    int cval, lval, rval;
    int mid()
    {
        return (left + right) / 2;
    }
}tree[MAXN * 3];
void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    tree[idx].cval = tree[idx].lval = tree[idx].rval = r - l + 1;
    tree[idx].delay = -1;//0 or 1 or -1
    if(l == r) return;
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
}
void pushdown(int idx)
{
    int l = LL(idx), r = RR(idx);
    tree[l].cval = tree[l].lval = tree[l].rval = tree[idx].delay * (tree[l].right - tree[l].left + 1);
    tree[l].delay = tree[idx].delay;
    tree[r].cval = tree[r].lval = tree[r].rval = tree[idx].delay * (tree[r].right - tree[r].left + 1);
    tree[r].delay = tree[idx].delay;
    tree[idx].delay = -1;
}
void update_info(int idx)
{
    int l = LL(idx), r = RR(idx);
    tree[idx].lval = tree[l].lval;
    if(tree[l].lval == tree[l].right - tree[l].left + 1)  tree[idx].lval += tree[r].lval;
    tree[idx].rval = tree[r].rval;
    if(tree[r].rval == tree[r].right - tree[r].left + 1)  tree[idx].rval += tree[l].rval;
    tree[idx].cval = max(tree[l].cval, tree[r].cval);
    tree[idx].cval = max(tree[idx].cval, tree[l].rval + tree[r].lval);
}
void update(int l, int r, int c, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        tree[idx].cval = tree[idx].lval = tree[idx].rval = c * (tree[idx].right - tree[idx].left + 1);
        tree[idx].delay = c;
        return;
    }
    if(tree[idx].delay != -1)  pushdown(idx);
    int mid = tree[idx].mid();
    if(r > mid)  update(l, r, c, RR(idx));
    if(l <= mid)  update(l, r, c, LL(idx));
    update_info(idx);
}
int query(int c, int idx)
{
    if(tree[idx].left == tree[idx].right)
    {
        if(c == 1) return tree[idx].left;
        return 0;
    }

    if(tree[idx].delay != -1)  pushdown(idx);
    int mid = tree[idx].mid();
    int l = LL(idx), r = RR(idx);
    if(tree[l].cval >= c) return query(c, LL(idx));
    else if(tree[l].rval + tree[r].lval >= c)  return tree[l].right - tree[l].rval + 1;
    else if(tree[r].cval >= c) return query(c, RR(idx));
    else return 0;
}
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        build(1, n, 1);
        int a, b, c;
        for(int i = 0; i < m; i++)
        {
            scanf("%d", &a);
            if(a == 1)
            {
                scanf("%d", &b);
                int ans = query(b, 1);
                printf("%d\n", ans);
                if(ans != 0) update(ans, ans + b - 1, 0, 1);
            }
            else
            {
                scanf("%d%d", &b, &c);
                update(b, b + c - 1, 1, 1);
            }
            //printf("%d\n", tree[1].cval);
        }
    }
    return 0;
}
/*HDU 1540
与前面那题Hotel相似。
单点更新,查询方式稍微有些区别,变化不大。
*/
#include<stdio.h>
#include<string.h>
#define LL(x)  (x<<1)
#define RR(x)  (x<<1|1)
int stack[50010],n,m;

struct Seg_Tree
{
    int l,r;
    int cval,lval,rval;
    void doit(int st)  {  cval=lval=rval=( st==1? 0 : dis() ) ;}
    int dis() { return (r-l+1) ;}
    int mid() { return (l+r)/2 ;}
}tree[50010*3];

int max(int a,int b)
{
    if(a>b)   return a;
    return b;
}

void build(int left,int right,int idx)
{
     tree[idx].l=left;
     tree[idx].r=right;
     tree[idx].doit(0);
     if(left==right)   return;
     int mid=tree[idx].mid();
     build(left,mid,LL(idx));
     build(mid+1,right,RR(idx));
}

void update(int x,int st,int idx)
{
     if(tree[idx].l==tree[idx].r)
     {
         tree[idx].doit(st);
         return ;
     }
     int mid=tree[idx].mid();
     if(x<=mid)  update(x,st,LL(idx));
     else  update(x,st,RR(idx));
     tree[idx].cval=max(tree[LL(idx)].rval+tree[RR(idx)].lval,
                        max(tree[LL(idx)].cval,tree[RR(idx)].cval));
     tree[idx].lval=tree[LL(idx)].lval;
     tree[idx].rval=tree[RR(idx)].rval;
     if(tree[LL(idx)].cval==tree[LL(idx)].dis()) tree[idx].lval+=tree[RR(idx)].lval;
     if(tree[RR(idx)].cval==tree[RR(idx)].dis()) tree[idx].rval+=tree[LL(idx)].rval;
}

int query(int x,int idx)
{
     if(tree[idx].l==tree[idx].r || tree[idx].cval==0 || tree[idx].cval==tree[idx].dis() )
     {
         return tree[idx].cval;
     }
     int mid=tree[idx].mid();
     if(x<=mid)
     {
         if(x>tree[LL(idx)].r-tree[LL(idx)].rval)
             //return query(x,LL(idx))+query(tree[RR(idx)].l,RR(idx));
             return query(x,LL(idx))+tree[RR(idx)].lval;
         else
             return query(x,LL(idx));
     }
     else
     {
         if(x<tree[RR(idx)].l+tree[RR(idx)].lval)
             //return query(tree[LL(idx)].r,LL(idx))+query(x,RR(idx));
             return query(x,RR(idx))+tree[LL(idx)].rval;
         else
             return query(x,RR(idx));
     }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(tree,0,sizeof(tree));
        memset(stack,0,sizeof(stack));
        int num=0;
        build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            char ch[2];
            scanf("%s",&ch);
            if(ch[0]=='D')
            {
                int x;
                scanf("%d",&x);
                update(x,1,1);
                stack[num++]=x;
            }
            else
            if(ch[0]=='Q')
            {
                int x;
                scanf("%d",&x);
                printf("%d\n",query(x,1));
            }
            else
            {
                if(num==0)  continue;
                update(stack[--num],0,1);
            }
        }
    }
    return 0;
}


/*
其实就是HOTEL的加强版,甚至于HOTEL的3个函数都没有任何变化。
内存共四个指令,第一次是New  x就是找一段长为X的最左边的区间,这个和HOTEL是没有区别,还是用那三个函数找到最左边的区间并加以更新,ST=1
第二个指令是Free  x就是找一个包含X的区间,咋一看以为要重写一个QUERY函数,其实没有必要,使用VECTOR数组保存下每次占领的区间,并且由于VECTOR是向量,可以删除中间的,并任意在中间加区间,十分方便。那我们现在向量里找到那个区间,接着进行更新,ST=0
第三个指令是Get x就是找到第X个区间的范围,用VECTOR的记录很快就能找到
第四个指令Reset,很方面,更新一下即可
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define LL(x) (x << 1)
#define RR(x) ((x << 1) | 1)
const int MAXN = 50000 + 1234;
using namespace std;

struct EDGE
{
    int begin, end;
};
vector<EDGE> que;
struct Seg_Tree
{
    int left, right;
    int lval, rval, cval;
    int delay;
    int mid()
    {
        return (left + right) / 2;
    }
} tree[MAXN * 3];

void build(int l, int r, int idx)
{
    tree[idx].left = l;
    tree[idx].right = r;
    tree[idx].lval = tree[idx].rval = tree[idx].cval = tree[idx].right - tree[idx].left + 1;
    tree[idx].delay = -1;
    if(l == r)  return;
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid + 1, r, RR(idx));
}

void pushdown(int idx)
{
    int l = LL(idx), r= RR(idx);
    tree[l].delay = tree[r].delay = tree[idx].delay;
    tree[l].cval = tree[l].lval = tree[l].rval = tree[idx].delay * (tree[l].right - tree[l].left + 1);
    tree[r].cval = tree[r].lval = tree[r].rval = tree[idx].delay * (tree[r].right - tree[r].left + 1);
    tree[idx].delay = -1;
}

void updateinfo(int idx)
{
    int l = LL(idx), r= RR(idx);
    tree[idx].cval = max(tree[l].cval, tree[r].cval);
    tree[idx].cval = max(tree[idx].cval, tree[l].rval + tree[r].lval);
    tree[idx].lval = tree[l].lval;
    if(tree[l].lval == tree[l].right - tree[l].left + 1)  tree[idx].lval += tree[r].lval;
    tree[idx].rval = tree[r].rval;
    if(tree[r].rval == tree[r].right - tree[r].left + 1)  tree[idx].rval += tree[l].rval;
}

void update(int l, int r, int c, int idx)
{
    if(l <= tree[idx].left && tree[idx].right <= r)
    {
        tree[idx].delay = c;
        tree[idx].cval = tree[idx].lval = tree[idx].rval = c * (tree[idx].right - tree[idx].left + 1);
        return;
    }
    if(tree[idx].delay != -1)  pushdown(idx);
    int mid = tree[idx].mid();
    if(l <= mid)  update(l, r, c, LL(idx));
    if(r > mid) update(l, r, c, RR(idx));
    updateinfo(idx);
}

int query(int x, int idx)
{
    if(tree[idx].left == tree[idx].right)
    {
        return tree[idx].left;
    }
    if(tree[idx].delay != -1)  pushdown(idx);
    int mid = tree[idx].mid();
    int l = LL(idx), r = RR(idx);
    if(tree[l].cval >= x)  return query(x, l);
    else if(tree[l].rval + tree[r].lval >= x) return mid - tree[l].rval + 1;
    else if(tree[r].cval >= x) return query(x, r);
    else return -1;//no possible
}

int half_search(int x)
{
    int left = 0, right = que.size() - 1;
    while(left <= right)
    {
        int mid = (left + right) / 2;
        if(que[mid].begin <= x) left = mid + 1;
        else right = mid - 1;
    }
    return left;
    //left是第一个begin大于x的区间(不等于),注意特殊情况就是队列为空,只有1个的时候也成立
}

int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        que.clear();
        build(1, n, 1);
        char s[10];
        int x;
        for(int i = 0; i < m; i++)
        {
            scanf("%s", s);
            if(strcmp(s, "New") == 0)
            {
                scanf("%d", &x);
                if(tree[1].cval < x) puts("Reject New");
                else
                {
                    EDGE tmp;
                    tmp.begin = query(x, 1);
                    tmp.end = tmp.begin + x - 1;
                    int pos = half_search(tmp.begin);
                    que.insert(que.begin() + pos, tmp);
                    update(tmp.begin, tmp.end, 0, 1);
                    printf("New at %d\n", tmp.begin);
                }
            }
            else if(strcmp(s, "Free") == 0)
            {
                scanf("%d", &x);
                int pos = half_search(x) - 1;
                if(pos < 0 || que[pos].end < x) puts("Reject Free");
                else
                {
                    update(que[pos].begin, que[pos].end, 1, 1);
                    printf("Free from %d to %d\n", que[pos].begin, que[pos].end);
                    que.erase(que.begin() + pos, que.begin() + pos + 1);
                }
            }
            else if(strcmp(s, "Get") == 0)
            {
                scanf("%d", &x);
                if(x > que.size())  puts("Reject Get");
                else
                {
                    printf("Get at %d\n", que[--x].begin);
                }
            }
            else
            {
                puts("Reset Now");
                que.clear();
                update(1, n, 1, 1);
            }
        }
        puts("");
    }
    return 0;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值