zoukankan      html  css  js  c++  java
  • zkw线段树专题

    题目来自大神博客的线段树专题

    http://www.notonlysuccess.com/index.php/segment-tree-complete/

    hdu1166 敌兵布阵
    题意:O(-1)
    思路:O(-1)
    线段树功能:update:单点增减 query:区间求和

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <utility>
    #include <queue>
    #include <stack>
    using namespace std;
    const int INF=1<<30;
    const double eps=1e-6;
    const int N = 50010;
    int sum[N<<2],n,M;
    
    void add(int x,int v)
    {
        for(x+=M;x;x>>=1)
            sum[x]+=v;
    }
    int query(int l,int r)
    {
        int res=0;
        for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) res+=sum[l^1];
            if(r&1) res+=sum[r^1];
        }
        return res;
    }
    void run()
    {
        scanf("%d",&n);
        for(M=1;M<=n+1;M*=2);
        memset(sum,0,sizeof(sum));
        int x,y;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            add(i,x);
        }
        char s[15];
        static int cas=1;
        printf("Case %d:
    ",cas++);
        while(scanf("%s",s)!=EOF && s[0]!='E')
        {
            scanf("%d%d",&x,&y);
            if(s[0]=='Q')   printf("%d
    ",query(x,y));
            else if(s[0]=='A') add(x,y);
            else  add(x,-y);
        }
    }
    
    int main()
    {
    //    freopen("case.txt","r",stdin);
        int _;
        scanf("%d",&_);
        while(_--)
            run();
        return 0;
    }
    View Code

    PS: 第一次交RE了一次,原因是,题目的n范围是5*10^5,我只开了数组比这个数的两倍大一点。但是zkw要求范围是2的k次幂那样的,所以开数组要开大点吧

    hdu1754 I Hate It
    题意:O(-1)
    思路:O(-1)
    线段树功能:update:单点替换 query:区间最值

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <utility>
    #include <queue>
    #include <stack>
    using namespace std;
    const int INF=1<<30;
    const double eps=1e-6;
    const int N = 200000;
    
    int mes[N<<2],n,m,M;
    
    void update(int x,int v)
    {
        x+=M;mes[x]=v;
        for(x>>=1;x;x>>=1)
            mes[x]=max(mes[x<<1],mes[x<<1|1]);
    }
    int query(int l,int r)
    {
        int res=0;
        for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) res=max(res,mes[l^1]);
            if(r&1) res=max(res,mes[r^1]);
        }
        return res;
    }
    
    void run()
    {
        for(M=1;M<=n+1;M<<=1);
        memset(mes,0,sizeof(mes));
        int x,y;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            update(i,x);
        }
        char s[5];
        while(m--)
        {
            scanf("%s%d%d",s,&x,&y);
            if(s[0]=='Q')   printf("%d
    ",query(x,y));
            else update(x,y);
        }
    }
    
    int main()
    {
    //    freopen("case.txt","r",stdin);
        while(scanf("%d%d",&n,&m)!=EOF)
            run();
        return 0;
    }
    View Code

    顺利1Y

    hdu1394 Minimum Inversion Number
    题意:求Inversion后的最小逆序数
    思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解。线段树是用在求最初逆序数上。递推方法详细在下面
    线段树功能:update:单点增减 query:区间求和

    递推: 因为题目总是把第一个数移到最后一个位置,所以原来比它小的数(和它构成逆序)在移动之后就不是逆序了,而原来比它大的数(不和它构成逆序)在移动之后就是逆序了,这样sum就变化了: Sum=sum-(low[a[i]])+(up[a[i]]);   显然在序列0,1,2,…..n-1中  比a[i]小的数的个数是 Low[a[i]]=a[i];  比a[i]大的数的个数是 up[a[i]]=n-a[i]-1;   题目要求是循环移动n次,那么只要写个for,把a[0],a[1],a[2]……a[n-1]都移动一遍,sum进行n次上面的公式运算,同时记录最小值,就是最小逆序数了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <utility>
    #include <queue>
    #include <stack>
    using namespace std;
    const int INF=1<<30;
    const double eps=1e-6;
    const int N = 5010;
    int sum[N<<2],n,M;
    int a[N];
    
    inline void add(int x)
    {
        for(x+=M;x;x>>=1)
            ++sum[x];
    }
    inline int query(int l,int r)
    {
        int res=0;
        for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) res+=sum[l^1];
            if(r&1) res+=sum[r^1];
        }
        return res;
    }
    
    void run()
    {
        int s=0;
        memset(sum,0,sizeof(sum));
        for(M=1;M<=n+1;M<<=1);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            ++a[i];//注意后面add的时候不能在0位置上add
            if(a[i]!=n)
                s+=query(a[i]+1,n);
            add(a[i]);
        }
        int ans=s;
        for(int i=1;i<=n;++i)
        {
            s = s + (n - a[i]) - (a[i] - 1);
            if(s<ans)   ans=s;
        }
        printf("%d
    ",ans);
    }
    
    int main()
    {
    //    freopen("case.txt","r",stdin);
        while(scanf("%d",&n)!=EOF)
            run();
        return 0;
    }
    View Code

    一个要注意的地方是zkw不能在0位置操作,所以应该把a[i]都加一

    hdu2795 Billboard
    题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
    思路:每次找到最大值的位子,然后减去L
    线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)

    跪了这个问题暂时没想到zkw怎么搞,这个是要根据当前区间最值来判断是去左子树还是右子树找,需要自顶向下的递归

    //---------其他题目---------//

    hdu4366 

    详细题解: hdu4366

    需要用到线段树

    单点更新,区间最值

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    using namespace std;
    const int N = 50010;
    
    struct _edge{
        int to,next;
    };
    _edge edge[N*2];
    int ecnt,head[N];
    void addedge(int u,int v)
    {
        edge[ecnt].to = v;
        edge[ecnt].next = head[u];
        head[u] = ecnt++;
    }
    struct node{
        int id,a,b,l,r;
        friend bool operator < (const node &a, const node &b)
        {
            return a.a>b.a;
        }
    };
    
    int n,m,M;
    int zkw[N*10][2];
    node man[N];
    int ans[N];
    int dfscnt;
    void dfs(int u,int fa)
    {
        man[u].l = dfscnt++;
        for(int e=head[u];e!=-1;e=edge[e].next)
        {
            int &v = edge[e].to;
            if(v==fa) continue;
            dfs(v,u);
        }
        man[u].r = dfscnt++;
    }
    
    void add(int x,int a,int b)
    {
        for(x+=M;x;x>>=1)
            if(zkw[x][0]<a)
                zkw[x][0]=a,zkw[x][1]=b;
    }
    int query(int l,int r)
    {
        int a,b;
        a=b=-1;
        for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1 && zkw[l^1][0]>a) a=zkw[l^1][0],b=zkw[l^1][1];
            if(r&1 && zkw[r^1][0]>a) a=zkw[r^1][0],b=zkw[r^1][1];
        }
        return b;
    }
    
    void run()
    {
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        ecnt=0;
        int a,b,c;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            addedge(a,i);
            addedge(i,a);
            man[i].a=c;
            man[i].b=b;
            man[i].id=i;
        }
        dfscnt=1;
        dfs(0,-1);
    //    for(int i=0;i<n;i++)
    //        printf("%d %d %d
    ",i,man[i].l,man[i].r);
        sort(man+1,man+n);
    
        for(M=1;M<=dfscnt+1;M*=2);
        memset(zkw,-1,sizeof(zkw));
    
        stack<int> stk;
        stk.push(1);
        ans[man[1].id]=-1;
        for(int i=2;i<n;i++)
        {
            if(man[i].a!=man[i-1].a)
            {
                while(!stk.empty())
                {
                    int u = stk.top(); stk.pop();
                    add(man[u].l,man[u].b,man[u].id);
                    add(man[u].r,man[u].b,man[u].id);
                }
            }
            stk.push(i);
            ans[man[i].id] = query(man[i].l,man[i].r);
        }
        while(m--)
        {
            scanf("%d",&a);
            printf("%d
    ",ans[a]);
        }
    }
    
    int main()
    {
        freopen("case.txt","r",stdin);
        int _;
        scanf("%d",&_);
        while(_--)
            run();
        return 0;
    }
    View Code
  • 相关阅读:
    bzoj1615 [Usaco2008 Mar]The Loathesome Hay Baler麻烦的干草打包机
    bzoj3402 [Usaco2009 Open]Hide and Seek 捉迷藏
    CF B. Planning The Expedition
    Codeforces ~ 1009C ~ Annoying Present (贪心)
    Codeforces Round#498(Div.3)D. Two Strings Swaps
    牛客Another Distinct Values
    牛客多校第四场 G Maximum Mode
    可持化永久树 的 STL ( rope )
    KMP算法 (字符串的匹配)
    求(3+开根5) N次方的整数部分最后3位
  • 原文地址:https://www.cnblogs.com/someblue/p/3918581.html
Copyright © 2011-2022 走看看